From nobody Wed Feb 11 16:10:13 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 91366C77B7C for ; Mon, 8 May 2023 01:17:58 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232425AbjEHBR4 (ORCPT ); Sun, 7 May 2023 21:17:56 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:37080 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232166AbjEHBRg (ORCPT ); Sun, 7 May 2023 21:17:36 -0400 Received: from bombadil.infradead.org (bombadil.infradead.org [IPv6:2607:7c80:54:3::133]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 9AA9F4698; Sun, 7 May 2023 18:17:34 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=bombadil.20210309; h=Sender:Content-Transfer-Encoding: MIME-Version:References:In-Reply-To:Message-Id:Date:Subject:Cc:To:From: Reply-To:Content-Type:Content-ID:Content-Description; bh=kBqqORDo5ZDeQubFLWt/Ze74JpFUmhricU9x7bL4UTQ=; b=h6trr0sC7qNp8uHXMnyvLn/Jan KuDgv/M0kH9YyEtN4IrpZFJUwK1NTw7h9L9jpf6EUCv1sZrwsCz+lMaZc+aH4aVNg8nnH0ma+sRJB ylWv14+go3Hzo+xUegcVMxLMqWhtgrChqPj+Aev5wfVx5RXmksHRgOxgoXLwDVIM45xCWi+pFwiwe LMLVkKI+DfSF+H3RTMBIVKVxTX8GXCADgFs3jMf8WRo9048F/FFDL9WYOYaPNRePTBmbOVNGzWUnz aZ6/KzqhZ9w8lM7pexORnK8MU4U5TMyUCnGr2uR933XScy2l6La3PNEao+QMr6LHDIgRHZyNVQFuY lycRanxA==; Received: from mcgrof by bombadil.infradead.org with local (Exim 4.96 #2 (Red Hat Linux)) id 1pvpV7-00GvYy-2e; Mon, 08 May 2023 01:17:17 +0000 From: Luis Chamberlain To: hch@infradead.org, djwong@kernel.org, sandeen@sandeen.net, song@kernel.org, rafael@kernel.org, gregkh@linuxfoundation.org, viro@zeniv.linux.org.uk, jack@suse.cz, jikos@kernel.org, bvanassche@acm.org, ebiederm@xmission.com Cc: mchehab@kernel.org, keescook@chromium.org, p.raghav@samsung.com, da.gomez@samsung.com, linux-fsdevel@vger.kernel.org, kernel@tuxforce.de, kexec@lists.infradead.org, linux-kernel@vger.kernel.org, Luis Chamberlain Subject: [PATCH 1/6] fs: unify locking semantics for fs freeze / thaw Date: Sun, 7 May 2023 18:17:12 -0700 Message-Id: <20230508011717.4034511-2-mcgrof@kernel.org> X-Mailer: git-send-email 2.38.1 In-Reply-To: <20230508011717.4034511-1-mcgrof@kernel.org> References: <20230508011717.4034511-1-mcgrof@kernel.org> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: Luis Chamberlain Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" Right now freeze_super() and thaw_super() are called with different locking contexts. To expand on this is messy, so just unify the requirement to require grabbing an active reference and keep the superblock locked. Suggested-by: Christoph Hellwig Signed-off-by: Luis Chamberlain --- block/bdev.c | 5 +++- fs/f2fs/gc.c | 5 ++++ fs/gfs2/super.c | 9 +++++-- fs/gfs2/sys.c | 6 +++++ fs/gfs2/util.c | 5 ++++ fs/ioctl.c | 12 ++++++++-- fs/super.c | 62 ++++++++++++++++++------------------------------- 7 files changed, 60 insertions(+), 44 deletions(-) diff --git a/block/bdev.c b/block/bdev.c index 21c63bfef323..dc54a2a1c46e 100644 --- a/block/bdev.c +++ b/block/bdev.c @@ -251,7 +251,7 @@ int freeze_bdev(struct block_device *bdev) error =3D sb->s_op->freeze_super(sb); else error =3D freeze_super(sb); - deactivate_super(sb); + deactivate_locked_super(sb); =20 if (error) { bdev->bd_fsfreeze_count--; @@ -289,6 +289,8 @@ int thaw_bdev(struct block_device *bdev) sb =3D bdev->bd_fsfreeze_sb; if (!sb) goto out; + if (!get_active_super(bdev)) + goto out; =20 if (sb->s_op->thaw_super) error =3D sb->s_op->thaw_super(sb); @@ -298,6 +300,7 @@ int thaw_bdev(struct block_device *bdev) bdev->bd_fsfreeze_count++; else bdev->bd_fsfreeze_sb =3D NULL; + deactivate_locked_super(sb); out: mutex_unlock(&bdev->bd_fsfreeze_mutex); return error; diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c index 61c5f9d26018..e31d6791d3e3 100644 --- a/fs/f2fs/gc.c +++ b/fs/f2fs/gc.c @@ -2166,7 +2166,10 @@ int f2fs_resize_fs(struct f2fs_sb_info *sbi, __u64 b= lock_count) if (err) return err; =20 + if (!get_active_super(sbi->sb->s_bdev)) + return -ENOTTY; freeze_super(sbi->sb); + f2fs_down_write(&sbi->gc_lock); f2fs_down_write(&sbi->cp_global_sem); =20 @@ -2217,6 +2220,8 @@ int f2fs_resize_fs(struct f2fs_sb_info *sbi, __u64 bl= ock_count) out_err: f2fs_up_write(&sbi->cp_global_sem); f2fs_up_write(&sbi->gc_lock); + /* We use the same active reference from freeze */ thaw_super(sbi->sb); + deactivate_locked_super(sbi->sb); return err; } diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index 5eed8c237500..e57cb593e2f3 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c @@ -676,7 +676,12 @@ void gfs2_freeze_func(struct work_struct *work) struct gfs2_sbd *sdp =3D container_of(work, struct gfs2_sbd, sd_freeze_wo= rk); struct super_block *sb =3D sdp->sd_vfs; =20 - atomic_inc(&sb->s_active); + if (!get_active_super(sb->s_bdev)) { + fs_info(sdp, "GFS2: couldn't grap super for thaw for filesystem\n"); + gfs2_assert_withdraw(sdp, 0); + return; + } + error =3D gfs2_freeze_lock(sdp, &freeze_gh, 0); if (error) { gfs2_assert_withdraw(sdp, 0); @@ -690,7 +695,7 @@ void gfs2_freeze_func(struct work_struct *work) } gfs2_freeze_unlock(&freeze_gh); } - deactivate_super(sb); + deactivate_locked_super(sb); clear_bit_unlock(SDF_FS_FROZEN, &sdp->sd_flags); wake_up_bit(&sdp->sd_flags, SDF_FS_FROZEN); return; diff --git a/fs/gfs2/sys.c b/fs/gfs2/sys.c index 454dc2ff8b5e..cbb71c3520c0 100644 --- a/fs/gfs2/sys.c +++ b/fs/gfs2/sys.c @@ -164,6 +164,9 @@ static ssize_t freeze_store(struct gfs2_sbd *sdp, const= char *buf, size_t len) if (!capable(CAP_SYS_ADMIN)) return -EPERM; =20 + if (!get_active_super(sb->s_bdev)) + return -ENOTTY; + switch (n) { case 0: error =3D thaw_super(sdp->sd_vfs); @@ -172,9 +175,12 @@ static ssize_t freeze_store(struct gfs2_sbd *sdp, cons= t char *buf, size_t len) error =3D freeze_super(sdp->sd_vfs); break; default: + deactivate_locked_super(sb); return -EINVAL; } =20 + deactivate_locked_super(sb); + if (error) { fs_warn(sdp, "freeze %d error %d\n", n, error); return error; diff --git a/fs/gfs2/util.c b/fs/gfs2/util.c index 7a6aeffcdf5c..3a0cd5e9ad84 100644 --- a/fs/gfs2/util.c +++ b/fs/gfs2/util.c @@ -345,10 +345,15 @@ int gfs2_withdraw(struct gfs2_sbd *sdp) set_bit(SDF_WITHDRAW_IN_PROG, &sdp->sd_flags); =20 if (sdp->sd_args.ar_errors =3D=3D GFS2_ERRORS_WITHDRAW) { + if (!get_active_super(sb->s_bdev)) { + fs_err(sdp, "could not grab super on withdraw for file system\n"); + return -1; + } fs_err(sdp, "about to withdraw this file system\n"); BUG_ON(sdp->sd_args.ar_debug); =20 signal_our_withdraw(sdp); + deactivate_locked_super(sb); =20 kobject_uevent(&sdp->sd_kobj, KOBJ_OFFLINE); =20 diff --git a/fs/ioctl.c b/fs/ioctl.c index 5b2481cd4750..1d20af762e0d 100644 --- a/fs/ioctl.c +++ b/fs/ioctl.c @@ -386,6 +386,7 @@ static int ioctl_fioasync(unsigned int fd, struct file = *filp, static int ioctl_fsfreeze(struct file *filp) { struct super_block *sb =3D file_inode(filp)->i_sb; + int ret; =20 if (!ns_capable(sb->s_user_ns, CAP_SYS_ADMIN)) return -EPERM; @@ -394,10 +395,17 @@ static int ioctl_fsfreeze(struct file *filp) if (sb->s_op->freeze_fs =3D=3D NULL && sb->s_op->freeze_super =3D=3D NULL) return -EOPNOTSUPP; =20 + if (!get_active_super(sb->s_bdev)) + return -ENOTTY; + /* Freeze */ if (sb->s_op->freeze_super) - return sb->s_op->freeze_super(sb); - return freeze_super(sb); + ret =3D sb->s_op->freeze_super(sb); + ret =3D freeze_super(sb); + + deactivate_locked_super(sb); + + return ret; } =20 static int ioctl_fsthaw(struct file *filp) diff --git a/fs/super.c b/fs/super.c index 34afe411cf2b..0e9d48846684 100644 --- a/fs/super.c +++ b/fs/super.c @@ -39,8 +39,6 @@ #include #include "internal.h" =20 -static int thaw_super_locked(struct super_block *sb); - static LIST_HEAD(super_blocks); static DEFINE_SPINLOCK(sb_lock); =20 @@ -851,13 +849,13 @@ struct super_block *get_active_super(struct block_dev= ice *bdev) if (sb->s_bdev =3D=3D bdev) { if (!grab_super(sb)) goto restart; - up_write(&sb->s_umount); return sb; } } spin_unlock(&sb_lock); return NULL; } +EXPORT_SYMBOL_GPL(get_active_super); =20 struct super_block *user_get_super(dev_t dev, bool excl) { @@ -1024,13 +1022,13 @@ void emergency_remount(void) =20 static void do_thaw_all_callback(struct super_block *sb) { - down_write(&sb->s_umount); + if (!get_active_super(sb->s_bdev)) + return; if (sb->s_root && sb->s_flags & SB_BORN) { emergency_thaw_bdev(sb); - thaw_super_locked(sb); - } else { - up_write(&sb->s_umount); + thaw_super(sb); } + deactivate_locked_super(sb); } =20 static void do_thaw_all(struct work_struct *work) @@ -1636,10 +1634,13 @@ static void sb_freeze_unlock(struct super_block *sb= , int level) } =20 /** - * freeze_super - lock the filesystem and force it into a consistent state + * freeze_super - force a filesystem backed by a block device into a consi= stent state * @sb: the super to lock * - * Syncs the super to make sure the filesystem is consistent and calls the= fs's + * Used by filesystems and the kernel to freeze a fileystem backed by a bl= ock + * device into a consistent state. Callers must use get_active_super(bdev)= to + * lock the @sb and when done must unlock it with deactivate_locked_super(= ). + * Syncs the filesystem backed by the @sb and calls the filesystem's optio= nal * freeze_fs. Subsequent calls to this without first thawing the fs will = return * -EBUSY. * @@ -1672,22 +1673,15 @@ int freeze_super(struct super_block *sb) { int ret; =20 - atomic_inc(&sb->s_active); - down_write(&sb->s_umount); - if (sb->s_writers.frozen !=3D SB_UNFROZEN) { - deactivate_locked_super(sb); + if (sb->s_writers.frozen !=3D SB_UNFROZEN) return -EBUSY; - } =20 - if (!(sb->s_flags & SB_BORN)) { - up_write(&sb->s_umount); + if (!(sb->s_flags & SB_BORN)) return 0; /* sic - it's "nothing to do" */ - } =20 if (sb_rdonly(sb)) { /* Nothing to do really... */ sb->s_writers.frozen =3D SB_FREEZE_COMPLETE; - up_write(&sb->s_umount); return 0; } =20 @@ -1707,7 +1701,6 @@ int freeze_super(struct super_block *sb) sb->s_writers.frozen =3D SB_UNFROZEN; sb_freeze_unlock(sb, SB_FREEZE_PAGEFAULT); wake_up(&sb->s_writers.wait_unfrozen); - deactivate_locked_super(sb); return ret; } =20 @@ -1723,7 +1716,6 @@ int freeze_super(struct super_block *sb) sb->s_writers.frozen =3D SB_UNFROZEN; sb_freeze_unlock(sb, SB_FREEZE_FS); wake_up(&sb->s_writers.wait_unfrozen); - deactivate_locked_super(sb); return ret; } } @@ -1733,19 +1725,25 @@ int freeze_super(struct super_block *sb) */ sb->s_writers.frozen =3D SB_FREEZE_COMPLETE; lockdep_sb_freeze_release(sb); - up_write(&sb->s_umount); return 0; } EXPORT_SYMBOL(freeze_super); =20 -static int thaw_super_locked(struct super_block *sb) +/** + * thaw_super -- unlock a filesystem backed by a block device + * @sb: the super to thaw + * + * Used by filesystems and the kernel to thaw a fileystem backed by a block + * device. Callers must use get_active_super(bdev) to lock the @sb and when + * done must unlock it with deactivate_locked_super(). Once done, this mar= ks + * the filesystem as writeable. + */ +int thaw_super(struct super_block *sb) { int error; =20 - if (sb->s_writers.frozen !=3D SB_FREEZE_COMPLETE) { - up_write(&sb->s_umount); + if (sb->s_writers.frozen !=3D SB_FREEZE_COMPLETE) return -EINVAL; - } =20 if (sb_rdonly(sb)) { sb->s_writers.frozen =3D SB_UNFROZEN; @@ -1760,7 +1758,6 @@ static int thaw_super_locked(struct super_block *sb) printk(KERN_ERR "VFS:Filesystem thaw failed\n"); lockdep_sb_freeze_release(sb); - up_write(&sb->s_umount); return error; } } @@ -1769,21 +1766,8 @@ static int thaw_super_locked(struct super_block *sb) sb_freeze_unlock(sb, SB_FREEZE_FS); out: wake_up(&sb->s_writers.wait_unfrozen); - deactivate_locked_super(sb); return 0; } - -/** - * thaw_super -- unlock filesystem - * @sb: the super to thaw - * - * Unlocks the filesystem and marks it writeable again after freeze_super(= ). - */ -int thaw_super(struct super_block *sb) -{ - down_write(&sb->s_umount); - return thaw_super_locked(sb); -} EXPORT_SYMBOL(thaw_super); =20 /* --=20 2.39.2 From nobody Wed Feb 11 16:10:13 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id D012DC77B75 for ; Mon, 8 May 2023 01:18:01 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232432AbjEHBSA (ORCPT ); Sun, 7 May 2023 21:18:00 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:37110 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232203AbjEHBRj (ORCPT ); Sun, 7 May 2023 21:17:39 -0400 Received: from bombadil.infradead.org (bombadil.infradead.org [IPv6:2607:7c80:54:3::133]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 0FEDD4C37; Sun, 7 May 2023 18:17:38 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=bombadil.20210309; h=Sender:Content-Transfer-Encoding: MIME-Version:References:In-Reply-To:Message-Id:Date:Subject:Cc:To:From: Reply-To:Content-Type:Content-ID:Content-Description; bh=4ny1Qyd51EIZ58YKw3q+aAfCx7UcmGMIn0O7WwMNHtM=; b=lg0WARWgwU+mm2tnnN6Dq/28he w5uZvkZdp0uy1T+muLlsYh1Q4mSzQXIex+XOagdmo3bjiJsFC9+HUXEayvh9LzYc+VSK0sfeffn5D t02mGNTRzhVsksIk3KlMsRkiq2zhr07Dn5gP8bhmLUdKHttmkNzN8ZfefXL1KYtMxBLpteYbfZA2I 3M0zbi8B7xy5L9bHuLX7y2YNSOFi2GSuYdKKYycbYd3R/EnKyYZsniInQHFBjFOVduih0Ffoy6g63 EiF9669UTNMH4SfH0HQMqKy0t5sGQMcM5HWCyYzpZ3nJ6kAyYXrhGELuRM9M/MYKOSbOFcaJsIA2Z rPj/+T+Q==; Received: from mcgrof by bombadil.infradead.org with local (Exim 4.96 #2 (Red Hat Linux)) id 1pvpV7-00GvZ0-2m; Mon, 08 May 2023 01:17:17 +0000 From: Luis Chamberlain To: hch@infradead.org, djwong@kernel.org, sandeen@sandeen.net, song@kernel.org, rafael@kernel.org, gregkh@linuxfoundation.org, viro@zeniv.linux.org.uk, jack@suse.cz, jikos@kernel.org, bvanassche@acm.org, ebiederm@xmission.com Cc: mchehab@kernel.org, keescook@chromium.org, p.raghav@samsung.com, da.gomez@samsung.com, linux-fsdevel@vger.kernel.org, kernel@tuxforce.de, kexec@lists.infradead.org, linux-kernel@vger.kernel.org, Luis Chamberlain Subject: [PATCH 2/6] fs: add frozen sb state helpers Date: Sun, 7 May 2023 18:17:13 -0700 Message-Id: <20230508011717.4034511-3-mcgrof@kernel.org> X-Mailer: git-send-email 2.38.1 In-Reply-To: <20230508011717.4034511-1-mcgrof@kernel.org> References: <20230508011717.4034511-1-mcgrof@kernel.org> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: Luis Chamberlain Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" Provide helpers so that we can check a superblock frozen state. This will make subsequent changes easier to read. This makes no functional changes. Reviewed-by: Jan Kara Signed-off-by: Luis Chamberlain --- fs/ext4/ext4_jbd2.c | 2 +- fs/gfs2/sys.c | 2 +- fs/quota/quota.c | 4 ++-- fs/super.c | 6 +++--- fs/xfs/xfs_trans.c | 3 +-- include/linux/fs.h | 22 ++++++++++++++++++++++ 6 files changed, 30 insertions(+), 9 deletions(-) diff --git a/fs/ext4/ext4_jbd2.c b/fs/ext4/ext4_jbd2.c index 77f318ec8abb..ef441f15053b 100644 --- a/fs/ext4/ext4_jbd2.c +++ b/fs/ext4/ext4_jbd2.c @@ -72,7 +72,7 @@ static int ext4_journal_check_start(struct super_block *s= b) =20 if (sb_rdonly(sb)) return -EROFS; - WARN_ON(sb->s_writers.frozen =3D=3D SB_FREEZE_COMPLETE); + WARN_ON(sb_is_frozen(sb)); journal =3D EXT4_SB(sb)->s_journal; /* * Special case here: if the journal has aborted behind our diff --git a/fs/gfs2/sys.c b/fs/gfs2/sys.c index cbb71c3520c0..e80c827acd09 100644 --- a/fs/gfs2/sys.c +++ b/fs/gfs2/sys.c @@ -148,7 +148,7 @@ static ssize_t uuid_show(struct gfs2_sbd *sdp, char *bu= f) static ssize_t freeze_show(struct gfs2_sbd *sdp, char *buf) { struct super_block *sb =3D sdp->sd_vfs; - int frozen =3D (sb->s_writers.frozen =3D=3D SB_UNFROZEN) ? 0 : 1; + int frozen =3D sb_is_unfrozen(sb) ? 0 : 1; =20 return snprintf(buf, PAGE_SIZE, "%d\n", frozen); } diff --git a/fs/quota/quota.c b/fs/quota/quota.c index 052f143e2e0e..66ea23e15d93 100644 --- a/fs/quota/quota.c +++ b/fs/quota/quota.c @@ -890,13 +890,13 @@ static struct super_block *quotactl_block(const char = __user *special, int cmd) sb =3D user_get_super(dev, excl); if (!sb) return ERR_PTR(-ENODEV); - if (thawed && sb->s_writers.frozen !=3D SB_UNFROZEN) { + if (thawed && !sb_is_unfrozen(sb)) { if (excl) up_write(&sb->s_umount); else up_read(&sb->s_umount); wait_event(sb->s_writers.wait_unfrozen, - sb->s_writers.frozen =3D=3D SB_UNFROZEN); + sb_is_unfrozen(sb)); put_super(sb); goto retry; } diff --git a/fs/super.c b/fs/super.c index 0e9d48846684..46c6475fc765 100644 --- a/fs/super.c +++ b/fs/super.c @@ -905,7 +905,7 @@ int reconfigure_super(struct fs_context *fc) =20 if (fc->sb_flags_mask & ~MS_RMT_MASK) return -EINVAL; - if (sb->s_writers.frozen !=3D SB_UNFROZEN) + if (!(sb_is_unfrozen(sb))) return -EBUSY; =20 retval =3D security_sb_remount(sb, fc->security); @@ -929,7 +929,7 @@ int reconfigure_super(struct fs_context *fc) down_write(&sb->s_umount); if (!sb->s_root) return 0; - if (sb->s_writers.frozen !=3D SB_UNFROZEN) + if (!sb_is_unfrozen(sb)) return -EBUSY; remount_ro =3D !sb_rdonly(sb); } @@ -1673,7 +1673,7 @@ int freeze_super(struct super_block *sb) { int ret; =20 - if (sb->s_writers.frozen !=3D SB_UNFROZEN) + if (!sb_is_unfrozen(sb)) return -EBUSY; =20 if (!(sb->s_flags & SB_BORN)) diff --git a/fs/xfs/xfs_trans.c b/fs/xfs/xfs_trans.c index 8afc0c080861..26caeafc572f 100644 --- a/fs/xfs/xfs_trans.c +++ b/fs/xfs/xfs_trans.c @@ -267,8 +267,7 @@ xfs_trans_alloc( * Zero-reservation ("empty") transactions can't modify anything, so * they're allowed to run while we're frozen. */ - WARN_ON(resp->tr_logres > 0 && - mp->m_super->s_writers.frozen =3D=3D SB_FREEZE_COMPLETE); + WARN_ON(resp->tr_logres > 0 && sb_is_frozen(mp->m_super)); ASSERT(!(flags & XFS_TRANS_RES_FDBLKS) || xfs_has_lazysbcount(mp)); =20 diff --git a/include/linux/fs.h b/include/linux/fs.h index 21a981680856..90b5bdc4071a 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1621,6 +1621,28 @@ static inline bool sb_start_intwrite_trylock(struct = super_block *sb) return __sb_start_write_trylock(sb, SB_FREEZE_FS); } =20 +/** + * sb_is_frozen - is superblock frozen + * @sb: the super to check + * + * Returns true if the super is frozen. + */ +static inline bool sb_is_frozen(struct super_block *sb) +{ + return sb->s_writers.frozen =3D=3D SB_FREEZE_COMPLETE; +} + +/** + * sb_is_unfrozen - is superblock unfrozen + * @sb: the super to check + * + * Returns true if the super is unfrozen. + */ +static inline bool sb_is_unfrozen(struct super_block *sb) +{ + return sb->s_writers.frozen =3D=3D SB_UNFROZEN; +} + bool inode_owner_or_capable(struct mnt_idmap *idmap, const struct inode *inode); =20 --=20 2.39.2 From nobody Wed Feb 11 16:10:13 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 7EA06C77B75 for ; Mon, 8 May 2023 01:17:53 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232401AbjEHBRw (ORCPT ); Sun, 7 May 2023 21:17:52 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:37078 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231827AbjEHBRf (ORCPT ); Sun, 7 May 2023 21:17:35 -0400 Received: from bombadil.infradead.org (bombadil.infradead.org [IPv6:2607:7c80:54:3::133]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 78E3C4696; Sun, 7 May 2023 18:17:34 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=bombadil.20210309; h=Sender:Content-Transfer-Encoding: MIME-Version:References:In-Reply-To:Message-Id:Date:Subject:Cc:To:From: Reply-To:Content-Type:Content-ID:Content-Description; bh=7N2aWPQ8XCHjo4VaLBoJ4vkX7xgNUHvf+Che6sVxE/c=; b=Mk/AHci/Q3UUXoCjFDMPoLi29K mavuKQCge2eNvZIBFJUZPcgcVtyY0faVKurSaI/kHv5Ap9ASwox68N87P7y8BEl12UNJycciCBou0 6MUdQjNasce4sDW8Fe1tTBAFms95DrXOZFgCxPPqYDLI+rYy7BS3svFO7/PgCxBbzFp4T4V0IDxtM /aEEzy6BC72QC8tLW4A3IFHG2l1SS6DvXw99FamBjLYf8bk7SRV/zbkhrrXvlD7haiw7xR2aQHuSq /MtpYTgT1S76Sgb8+6PKGnZGcj0TpvzPgbgKyVA939aCwMxKGKdVkh8UeBJ4eLTjmBUVOPNixnh/t q7JYo6tQ==; Received: from mcgrof by bombadil.infradead.org with local (Exim 4.96 #2 (Red Hat Linux)) id 1pvpV7-00GvZ2-2u; Mon, 08 May 2023 01:17:17 +0000 From: Luis Chamberlain To: hch@infradead.org, djwong@kernel.org, sandeen@sandeen.net, song@kernel.org, rafael@kernel.org, gregkh@linuxfoundation.org, viro@zeniv.linux.org.uk, jack@suse.cz, jikos@kernel.org, bvanassche@acm.org, ebiederm@xmission.com Cc: mchehab@kernel.org, keescook@chromium.org, p.raghav@samsung.com, da.gomez@samsung.com, linux-fsdevel@vger.kernel.org, kernel@tuxforce.de, kexec@lists.infradead.org, linux-kernel@vger.kernel.org, Luis Chamberlain Subject: [PATCH 3/6] fs: distinguish between user initiated freeze and kernel initiated freeze Date: Sun, 7 May 2023 18:17:14 -0700 Message-Id: <20230508011717.4034511-4-mcgrof@kernel.org> X-Mailer: git-send-email 2.38.1 In-Reply-To: <20230508011717.4034511-1-mcgrof@kernel.org> References: <20230508011717.4034511-1-mcgrof@kernel.org> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: Luis Chamberlain Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" Userspace can initiate a freeze call using ioctls. If the kernel decides to freeze a filesystem later it must be able to distinguish if userspace had initiated the freeze, so that it does not unfreeze it later automatically on resume. Likewise if the kernel is initiating a freeze on its own it should *not* fail to freeze a filesystem if a user had already frozen it on our behalf. This same concept applies to thawing, even if its not possible for userspace to beat the kernel in thawing a filesystem. This logic however has never applied to userspace freezing and thawing, two consecutive userspace freeze calls will results in only the first one succeeding, so we must retain the same behaviour in userspace. This doesn't implement yet kernel initiated filesystem freeze calls, this will be done in subsequent calls. This change should introduce no functional changes, it just extends the definitions of a frozen filesystem to account for future kernel initiated filesystem freeze and let's us keep record of when userpace initiated it so the kernel can respect a userspace initiated freeze upon kernel initiated freeze and its respective thaw cycle. Reviewed-by: Jan Kara Signed-off-by: Luis Chamberlain --- block/bdev.c | 4 ++-- fs/f2fs/gc.c | 4 ++-- fs/gfs2/glops.c | 2 +- fs/gfs2/super.c | 2 +- fs/gfs2/sys.c | 4 ++-- fs/gfs2/util.c | 2 +- fs/ioctl.c | 4 ++-- fs/super.c | 29 +++++++++++++++++++++++++---- include/linux/fs.h | 16 ++++++++++++++-- 9 files changed, 50 insertions(+), 17 deletions(-) diff --git a/block/bdev.c b/block/bdev.c index dc54a2a1c46e..04f7b2c99845 100644 --- a/block/bdev.c +++ b/block/bdev.c @@ -250,7 +250,7 @@ int freeze_bdev(struct block_device *bdev) if (sb->s_op->freeze_super) error =3D sb->s_op->freeze_super(sb); else - error =3D freeze_super(sb); + error =3D freeze_super(sb, true); deactivate_locked_super(sb); =20 if (error) { @@ -295,7 +295,7 @@ int thaw_bdev(struct block_device *bdev) if (sb->s_op->thaw_super) error =3D sb->s_op->thaw_super(sb); else - error =3D thaw_super(sb); + error =3D thaw_super(sb, true); if (error) bdev->bd_fsfreeze_count++; else diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c index e31d6791d3e3..a5891055d85d 100644 --- a/fs/f2fs/gc.c +++ b/fs/f2fs/gc.c @@ -2168,7 +2168,7 @@ int f2fs_resize_fs(struct f2fs_sb_info *sbi, __u64 bl= ock_count) =20 if (!get_active_super(sbi->sb->s_bdev)) return -ENOTTY; - freeze_super(sbi->sb); + freeze_super(sbi->sb, true); =20 f2fs_down_write(&sbi->gc_lock); f2fs_down_write(&sbi->cp_global_sem); @@ -2221,7 +2221,7 @@ int f2fs_resize_fs(struct f2fs_sb_info *sbi, __u64 bl= ock_count) f2fs_up_write(&sbi->cp_global_sem); f2fs_up_write(&sbi->gc_lock); /* We use the same active reference from freeze */ - thaw_super(sbi->sb); + thaw_super(sbi->sb, true); deactivate_locked_super(sbi->sb); return err; } diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c index 01d433ed6ce7..8fd37508f9a0 100644 --- a/fs/gfs2/glops.c +++ b/fs/gfs2/glops.c @@ -584,7 +584,7 @@ static int freeze_go_sync(struct gfs2_glock *gl) if (gl->gl_state =3D=3D LM_ST_SHARED && !gfs2_withdrawn(sdp) && !test_bit(SDF_NORECOVERY, &sdp->sd_flags)) { atomic_set(&sdp->sd_freeze_state, SFS_STARTING_FREEZE); - error =3D freeze_super(sdp->sd_vfs); + error =3D freeze_super(sdp->sd_vfs, true); if (error) { fs_info(sdp, "GFS2: couldn't freeze filesystem: %d\n", error); diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index e57cb593e2f3..f2641891de43 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c @@ -687,7 +687,7 @@ void gfs2_freeze_func(struct work_struct *work) gfs2_assert_withdraw(sdp, 0); } else { atomic_set(&sdp->sd_freeze_state, SFS_UNFROZEN); - error =3D thaw_super(sb); + error =3D thaw_super(sb, true); if (error) { fs_info(sdp, "GFS2: couldn't thaw filesystem: %d\n", error); diff --git a/fs/gfs2/sys.c b/fs/gfs2/sys.c index e80c827acd09..9e0398f99674 100644 --- a/fs/gfs2/sys.c +++ b/fs/gfs2/sys.c @@ -169,10 +169,10 @@ static ssize_t freeze_store(struct gfs2_sbd *sdp, con= st char *buf, size_t len) =20 switch (n) { case 0: - error =3D thaw_super(sdp->sd_vfs); + error =3D thaw_super(sdp->sd_vfs, true); break; case 1: - error =3D freeze_super(sdp->sd_vfs); + error =3D freeze_super(sdp->sd_vfs, true); break; default: deactivate_locked_super(sb); diff --git a/fs/gfs2/util.c b/fs/gfs2/util.c index 3a0cd5e9ad84..be9705d618ec 100644 --- a/fs/gfs2/util.c +++ b/fs/gfs2/util.c @@ -191,7 +191,7 @@ static void signal_our_withdraw(struct gfs2_sbd *sdp) /* Make sure gfs2_unfreeze works if partially-frozen */ flush_work(&sdp->sd_freeze_work); atomic_set(&sdp->sd_freeze_state, SFS_FROZEN); - thaw_super(sdp->sd_vfs); + thaw_super(sdp->sd_vfs, true); } else { wait_on_bit(&i_gl->gl_flags, GLF_DEMOTE, TASK_UNINTERRUPTIBLE); diff --git a/fs/ioctl.c b/fs/ioctl.c index 1d20af762e0d..3cc79b82a5dc 100644 --- a/fs/ioctl.c +++ b/fs/ioctl.c @@ -401,7 +401,7 @@ static int ioctl_fsfreeze(struct file *filp) /* Freeze */ if (sb->s_op->freeze_super) ret =3D sb->s_op->freeze_super(sb); - ret =3D freeze_super(sb); + ret =3D freeze_super(sb, true); =20 deactivate_locked_super(sb); =20 @@ -418,7 +418,7 @@ static int ioctl_fsthaw(struct file *filp) /* Thaw */ if (sb->s_op->thaw_super) return sb->s_op->thaw_super(sb); - return thaw_super(sb); + return thaw_super(sb, true); } =20 static int ioctl_file_dedupe_range(struct file *file, diff --git a/fs/super.c b/fs/super.c index 46c6475fc765..16ccbb9dd230 100644 --- a/fs/super.c +++ b/fs/super.c @@ -1026,7 +1026,7 @@ static void do_thaw_all_callback(struct super_block *= sb) return; if (sb->s_root && sb->s_flags & SB_BORN) { emergency_thaw_bdev(sb); - thaw_super(sb); + thaw_super(sb, true); } deactivate_locked_super(sb); } @@ -1636,6 +1636,8 @@ static void sb_freeze_unlock(struct super_block *sb, = int level) /** * freeze_super - force a filesystem backed by a block device into a consi= stent state * @sb: the super to lock + * @usercall: whether or not userspace initiated this via an ioctl or if it + * was a kernel freeze * * Used by filesystems and the kernel to freeze a fileystem backed by a bl= ock * device into a consistent state. Callers must use get_active_super(bdev)= to @@ -1669,10 +1671,13 @@ static void sb_freeze_unlock(struct super_block *sb= , int level) * * sb->s_writers.frozen is protected by sb->s_umount. */ -int freeze_super(struct super_block *sb) +int freeze_super(struct super_block *sb, bool usercall) { int ret; =20 + if (!usercall && sb_is_frozen(sb)) + return 0; + if (!sb_is_unfrozen(sb)) return -EBUSY; =20 @@ -1682,6 +1687,7 @@ int freeze_super(struct super_block *sb) if (sb_rdonly(sb)) { /* Nothing to do really... */ sb->s_writers.frozen =3D SB_FREEZE_COMPLETE; + sb->s_writers.frozen_by_user =3D usercall; return 0; } =20 @@ -1699,6 +1705,7 @@ int freeze_super(struct super_block *sb) ret =3D sync_filesystem(sb); if (ret) { sb->s_writers.frozen =3D SB_UNFROZEN; + sb->s_writers.frozen_by_user =3D false; sb_freeze_unlock(sb, SB_FREEZE_PAGEFAULT); wake_up(&sb->s_writers.wait_unfrozen); return ret; @@ -1724,6 +1731,7 @@ int freeze_super(struct super_block *sb) * when frozen is set to SB_FREEZE_COMPLETE, and for thaw_super(). */ sb->s_writers.frozen =3D SB_FREEZE_COMPLETE; + sb->s_writers.frozen_by_user =3D usercall; lockdep_sb_freeze_release(sb); return 0; } @@ -1732,21 +1740,33 @@ EXPORT_SYMBOL(freeze_super); /** * thaw_super -- unlock a filesystem backed by a block device * @sb: the super to thaw + * @usercall: whether or not userspace initiated this thaw or if it was the + * kernel which initiated it * * Used by filesystems and the kernel to thaw a fileystem backed by a block * device. Callers must use get_active_super(bdev) to lock the @sb and when * done must unlock it with deactivate_locked_super(). Once done, this mar= ks * the filesystem as writeable. */ -int thaw_super(struct super_block *sb) +int thaw_super(struct super_block *sb, bool usercall) { int error; =20 - if (sb->s_writers.frozen !=3D SB_FREEZE_COMPLETE) + if (!usercall) { + /* + * If userspace initiated the freeze don't let the kernel + * thaw it on return from a kernel initiated freeze. + */ + if (sb_is_unfrozen(sb) || sb_is_frozen_by_user(sb)) + return 0; + } + + if (!sb_is_frozen(sb)) return -EINVAL; =20 if (sb_rdonly(sb)) { sb->s_writers.frozen =3D SB_UNFROZEN; + sb->s_writers.frozen_by_user =3D false; goto out; } =20 @@ -1763,6 +1783,7 @@ int thaw_super(struct super_block *sb) } =20 sb->s_writers.frozen =3D SB_UNFROZEN; + sb->s_writers.frozen_by_user =3D false; sb_freeze_unlock(sb, SB_FREEZE_FS); out: wake_up(&sb->s_writers.wait_unfrozen); diff --git a/include/linux/fs.h b/include/linux/fs.h index 90b5bdc4071a..d9b46c858103 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1146,6 +1146,7 @@ enum { =20 struct sb_writers { int frozen; /* Is sb frozen? */ + bool frozen_by_user; /* User freeze? */ wait_queue_head_t wait_unfrozen; /* wait for thaw */ struct percpu_rw_semaphore rw_sem[SB_FREEZE_LEVELS]; }; @@ -1632,6 +1633,17 @@ static inline bool sb_is_frozen(struct super_block *= sb) return sb->s_writers.frozen =3D=3D SB_FREEZE_COMPLETE; } =20 +/** + * sb_is_frozen_by_user - was the superblock frozen by userspace? + * @sb: the super to check + * + * Returns true if the super is frozen by userspace, such as an ioctl. + */ +static inline bool sb_is_frozen_by_user(struct super_block *sb) +{ + return sb_is_frozen(sb) && sb->s_writers.frozen_by_user; +} + /** * sb_is_unfrozen - is superblock unfrozen * @sb: the super to check @@ -2308,8 +2320,8 @@ extern int unregister_filesystem(struct file_system_t= ype *); extern int vfs_statfs(const struct path *, struct kstatfs *); extern int user_statfs(const char __user *, struct kstatfs *); extern int fd_statfs(int, struct kstatfs *); -extern int freeze_super(struct super_block *super); -extern int thaw_super(struct super_block *super); +extern int freeze_super(struct super_block *super, bool usercall); +extern int thaw_super(struct super_block *super, bool usercall); extern __printf(2, 3) int super_setup_bdi_name(struct super_block *sb, char *fmt, ...); extern int super_setup_bdi(struct super_block *sb); --=20 2.39.2 From nobody Wed Feb 11 16:10:13 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id E2C61C7EE26 for ; Mon, 8 May 2023 01:17:47 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232254AbjEHBRp (ORCPT ); Sun, 7 May 2023 21:17:45 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:37074 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230433AbjEHBRf (ORCPT ); Sun, 7 May 2023 21:17:35 -0400 Received: from bombadil.infradead.org (bombadil.infradead.org [IPv6:2607:7c80:54:3::133]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id BA51F468A; Sun, 7 May 2023 18:17:32 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=bombadil.20210309; h=Sender:Content-Transfer-Encoding: MIME-Version:References:In-Reply-To:Message-Id:Date:Subject:Cc:To:From: Reply-To:Content-Type:Content-ID:Content-Description; bh=PTHrGhg729vTgLExIgnS6GZIXZ79cZ7Du4oqbKrd5yA=; b=jOKays2+3gsfVEdCnQyXiTpGAB sy1Zi6r9fQIfiJ4jCm2+VzEZjYCNfHU5PD6+qjcHKiunwsIWh9DhztGtEeZaCb5WN9ltt3cvxYthN r1PrKvl6QvZDCwtPPgv8ViJ58AEj3sVk0FSYuqpu63DS1pn0iDKbZGLt7r9uL8jnfIieba69I6ZVm wKHLCjzwkyVHZRdf/1lH4u+Y8T2GJzli9hWGJ+gGxsjtxvg2twiMXWWBBbtWQWXHwy3sCaYYbhRwU pyqRY9qI1s8aRaOhEboXDXO7xSJ4d+mN3UbOxVgLF4+J3EhzEEFA8t+4hAoyL2cTDwJzoLCLYx9Qg AuuPq3GQ==; Received: from mcgrof by bombadil.infradead.org with local (Exim 4.96 #2 (Red Hat Linux)) id 1pvpV7-00GvZ4-32; Mon, 08 May 2023 01:17:17 +0000 From: Luis Chamberlain To: hch@infradead.org, djwong@kernel.org, sandeen@sandeen.net, song@kernel.org, rafael@kernel.org, gregkh@linuxfoundation.org, viro@zeniv.linux.org.uk, jack@suse.cz, jikos@kernel.org, bvanassche@acm.org, ebiederm@xmission.com Cc: mchehab@kernel.org, keescook@chromium.org, p.raghav@samsung.com, da.gomez@samsung.com, linux-fsdevel@vger.kernel.org, kernel@tuxforce.de, kexec@lists.infradead.org, linux-kernel@vger.kernel.org, Luis Chamberlain Subject: [PATCH 4/6] fs: move !SB_BORN check early on freeze and add for thaw Date: Sun, 7 May 2023 18:17:15 -0700 Message-Id: <20230508011717.4034511-5-mcgrof@kernel.org> X-Mailer: git-send-email 2.38.1 In-Reply-To: <20230508011717.4034511-1-mcgrof@kernel.org> References: <20230508011717.4034511-1-mcgrof@kernel.org> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: Luis Chamberlain Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" The SB_BORN flag added on vfs_get_tree() when a filesystem is about to be mounted. If a super_block lacks this flag there's nothing to do for that filesystem in terms of freezing or thawing. In subsequent patches support will be added to allow detecting failures for iterating over all super_blocks and freezing or thawing. Although that functionality will be be skipped when sb->s_bdi =3D=3D &noop_backing_dev_in= fo, and so SB_BORN will not be set, since we already check for SB_BORN on freeze just move that up earlier and to be consistent do the same on thaw too. We do this as these are user facing APIs, and although it would be incorrect to issue a freeze on a non-mounted sb, it is even stranger to get -EBUSY. Be consistent about this and bail early for !SB_BORN for freeze and thaw without failing. Signed-off-by: Luis Chamberlain --- fs/super.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/fs/super.c b/fs/super.c index 16ccbb9dd230..28c633b81f8f 100644 --- a/fs/super.c +++ b/fs/super.c @@ -1678,12 +1678,13 @@ int freeze_super(struct super_block *sb, bool userc= all) if (!usercall && sb_is_frozen(sb)) return 0; =20 + /* If the filesystem was not going to be mounted there is nothing to do */ + if (!(sb->s_flags & SB_BORN)) + return 0; + if (!sb_is_unfrozen(sb)) return -EBUSY; =20 - if (!(sb->s_flags & SB_BORN)) - return 0; /* sic - it's "nothing to do" */ - if (sb_rdonly(sb)) { /* Nothing to do really... */ sb->s_writers.frozen =3D SB_FREEZE_COMPLETE; @@ -1761,6 +1762,10 @@ int thaw_super(struct super_block *sb, bool usercall) return 0; } =20 + /* If the filesystem was not going to be mounted there is nothing to do */ + if (!(sb->s_flags & SB_BORN)) + return 0; + if (!sb_is_frozen(sb)) return -EINVAL; =20 --=20 2.39.2 From nobody Wed Feb 11 16:10:13 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 9C7BFC77B7C for ; Mon, 8 May 2023 01:17:50 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232331AbjEHBRt (ORCPT ); Sun, 7 May 2023 21:17:49 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:37076 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231624AbjEHBRf (ORCPT ); Sun, 7 May 2023 21:17:35 -0400 Received: from bombadil.infradead.org (bombadil.infradead.org [IPv6:2607:7c80:54:3::133]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E533F4692; Sun, 7 May 2023 18:17:33 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=bombadil.20210309; h=Sender:Content-Transfer-Encoding: MIME-Version:References:In-Reply-To:Message-Id:Date:Subject:Cc:To:From: Reply-To:Content-Type:Content-ID:Content-Description; bh=MQBqMg9ABCp7pDR5MHiqFyaBRKQveeMslSclfU7uPrc=; b=MvC8FF9/n/HakVu5oKPLJ2ZVxz Xp42ENNEf8J37Xp5gi7XSkaEjOPxEAbiiZGvLvZS1Ryoa313IgvKue8jNUUWXm4q9Zok7muvzRc0j 4Ja2yzkwpg42KbxDFp683ZK735f9W90iM1BDHjQjaMM7gX3u1Z85PbB13OMoxaPfr6TGmJCX5PnDW u2i3zET0FDORhzINnP8cGAF/eeRbBzkw7Ehd9JxbaC7K6MTGJDUk2GJvEGiWmL6i+I0pFWnveoUEt GK53/l2x59kAY24U1GYm1GWVSZVRLWxTUkAHxFxo8sUXFM1mIpeuDbUMv72PuDeNekOhYq8oVwJfh 26HfsNpg==; Received: from mcgrof by bombadil.infradead.org with local (Exim 4.96 #2 (Red Hat Linux)) id 1pvpV7-00GvZ6-3A; Mon, 08 May 2023 01:17:17 +0000 From: Luis Chamberlain To: hch@infradead.org, djwong@kernel.org, sandeen@sandeen.net, song@kernel.org, rafael@kernel.org, gregkh@linuxfoundation.org, viro@zeniv.linux.org.uk, jack@suse.cz, jikos@kernel.org, bvanassche@acm.org, ebiederm@xmission.com Cc: mchehab@kernel.org, keescook@chromium.org, p.raghav@samsung.com, da.gomez@samsung.com, linux-fsdevel@vger.kernel.org, kernel@tuxforce.de, kexec@lists.infradead.org, linux-kernel@vger.kernel.org, Luis Chamberlain Subject: [PATCH 5/6] fs: add iterate_supers_excl() and iterate_supers_reverse_excl() Date: Sun, 7 May 2023 18:17:16 -0700 Message-Id: <20230508011717.4034511-6-mcgrof@kernel.org> X-Mailer: git-send-email 2.38.1 In-Reply-To: <20230508011717.4034511-1-mcgrof@kernel.org> References: <20230508011717.4034511-1-mcgrof@kernel.org> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: Luis Chamberlain Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" There are use cases where we wish to traverse the superblock list but also capture errors, and in which case we want to avoid having our callers issue a lock themselves since we can do the locking for the callers. Provide a iterate_supers_excl() which calls a function with the write lock held. If an error occurs we capture it and propagate it. Likewise there are use cases where we wish to traverse the superblock list but in reverse order. The new iterate_supers_reverse_excl() helpers does this but also also captures any errors encountered. Reviewed-by: Jan Kara Signed-off-by: Luis Chamberlain --- fs/super.c | 91 ++++++++++++++++++++++++++++++++++++++++++++++ include/linux/fs.h | 2 + 2 files changed, 93 insertions(+) diff --git a/fs/super.c b/fs/super.c index 28c633b81f8f..d5eab6b38b03 100644 --- a/fs/super.c +++ b/fs/super.c @@ -753,6 +753,97 @@ void iterate_supers(void (*f)(struct super_block *, vo= id *), void *arg) spin_unlock(&sb_lock); } =20 +/** + * iterate_supers_excl - exclusively call func for all active superblocks + * @f: function to call + * @arg: argument to pass to it + * + * Scans the superblock list and calls given function, passing it + * locked superblock and given argument. Returns 0 unless an error + * occurred on calling the function on any superblock. + */ +int iterate_supers_excl(int (*f)(struct super_block *, void *), void *arg) +{ + struct super_block *sb, *p =3D NULL; + int error =3D 0; + + spin_lock(&sb_lock); + list_for_each_entry(sb, &super_blocks, s_list) { + if (hlist_unhashed(&sb->s_instances)) + continue; + sb->s_count++; + spin_unlock(&sb_lock); + + down_write(&sb->s_umount); + if (sb->s_root && (sb->s_flags & SB_BORN)) { + error =3D f(sb, arg); + if (error) { + up_write(&sb->s_umount); + spin_lock(&sb_lock); + __put_super(sb); + break; + } + } + up_write(&sb->s_umount); + + spin_lock(&sb_lock); + if (p) + __put_super(p); + p =3D sb; + } + if (p) + __put_super(p); + spin_unlock(&sb_lock); + + return error; +} + +/** + * iterate_supers_reverse_excl - exclusively calls func in reverse order + * @f: function to call + * @arg: argument to pass to it + * + * Scans the superblock list and calls given function, passing it + * locked superblock and given argument, in reverse order, and holding + * the s_umount write lock. Returns if an error occurred. + */ +int iterate_supers_reverse_excl(int (*f)(struct super_block *, void *), + void *arg) +{ + struct super_block *sb, *p =3D NULL; + int error =3D 0; + + spin_lock(&sb_lock); + list_for_each_entry_reverse(sb, &super_blocks, s_list) { + if (hlist_unhashed(&sb->s_instances)) + continue; + sb->s_count++; + spin_unlock(&sb_lock); + + down_write(&sb->s_umount); + if (sb->s_root && (sb->s_flags & SB_BORN)) { + error =3D f(sb, arg); + if (error) { + up_write(&sb->s_umount); + spin_lock(&sb_lock); + __put_super(sb); + break; + } + } + up_write(&sb->s_umount); + + spin_lock(&sb_lock); + if (p) + __put_super(p); + p =3D sb; + } + if (p) + __put_super(p); + spin_unlock(&sb_lock); + + return error; +} + /** * iterate_supers_type - call function for superblocks of given type * @type: fs type diff --git a/include/linux/fs.h b/include/linux/fs.h index d9b46c858103..22dd697ab703 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -2935,6 +2935,8 @@ extern struct super_block *get_active_super(struct bl= ock_device *bdev); extern void drop_super(struct super_block *sb); extern void drop_super_exclusive(struct super_block *sb); extern void iterate_supers(void (*)(struct super_block *, void *), void *); +extern int iterate_supers_excl(int (*f)(struct super_block *, void *), voi= d *arg); +extern int iterate_supers_reverse_excl(int (*)(struct super_block *, void = *), void *); extern void iterate_supers_type(struct file_system_type *, void (*)(struct super_block *, void *), void *); =20 --=20 2.39.2 From nobody Wed Feb 11 16:10:13 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 50D65C77B7C for ; Mon, 8 May 2023 01:17:40 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232177AbjEHBRg (ORCPT ); Sun, 7 May 2023 21:17:36 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:37066 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229852AbjEHBRe (ORCPT ); Sun, 7 May 2023 21:17:34 -0400 Received: from bombadil.infradead.org (bombadil.infradead.org [IPv6:2607:7c80:54:3::133]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 8D98A4223; Sun, 7 May 2023 18:17:32 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=bombadil.20210309; h=Sender:Content-Transfer-Encoding: MIME-Version:References:In-Reply-To:Message-Id:Date:Subject:Cc:To:From: Reply-To:Content-Type:Content-ID:Content-Description; bh=zV/X3tLmwQ3vkrJuBRI3Kmx6RRpx7xIxXORk1HlgcdM=; b=OWwZjPzlHo7TEPfwlAaYTUf9aj 38zu8BjZimyFpCYPssUK3/EJ9zhGMoUCwZ6O0HXh/YjLS7QDkpCrpiv2+9o9Nc+oBCLedZveIcoyZ 4uyb2EGJSSOa0Zxeb+ntcrjUOFT6ISS5zP6XaMmVXFnYRH6DwHVYt22Vb5adkXERJLzqBiMyIANUO iI1gpDLHZOKkvjMraKixrB4bGVw4Jl6YpaeGIQuaNRrPuhYxjvu+sD+o4l6It+EF+7BQH2H26JtVn 6OjvgRm7WDUD5zFp4bSe0LP/BuT7dQqgo4TLhPBEYRJfEEachilWpDb6xScWuWR6NVwx8Y6p9zNNR 6+n77wvw==; Received: from mcgrof by bombadil.infradead.org with local (Exim 4.96 #2 (Red Hat Linux)) id 1pvpV8-00GvZ8-04; Mon, 08 May 2023 01:17:18 +0000 From: Luis Chamberlain To: hch@infradead.org, djwong@kernel.org, sandeen@sandeen.net, song@kernel.org, rafael@kernel.org, gregkh@linuxfoundation.org, viro@zeniv.linux.org.uk, jack@suse.cz, jikos@kernel.org, bvanassche@acm.org, ebiederm@xmission.com Cc: mchehab@kernel.org, keescook@chromium.org, p.raghav@samsung.com, da.gomez@samsung.com, linux-fsdevel@vger.kernel.org, kernel@tuxforce.de, kexec@lists.infradead.org, linux-kernel@vger.kernel.org, Luis Chamberlain Subject: [PATCH 6/6] fs: add automatic kernel fs freeze / thaw and remove kthread freezing Date: Sun, 7 May 2023 18:17:17 -0700 Message-Id: <20230508011717.4034511-7-mcgrof@kernel.org> X-Mailer: git-send-email 2.38.1 In-Reply-To: <20230508011717.4034511-1-mcgrof@kernel.org> References: <20230508011717.4034511-1-mcgrof@kernel.org> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: Luis Chamberlain Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" Add support to automatically handle freezing and thawing filesystems during the kernel's suspend/resume cycle. This is needed so that we properly really stop IO in flight without races after userspace has been frozen. Without this we rely on kthread freezing and its semantics are loose and error prone. For instance, even though a kthread may use try_to_freeze() and end up being frozen we have no way of being sure that everything that has been spawned asynchronously from it (such as timers) have also been stopped as well. A long term advantage of also adding filesystem freeze / thawing supporting during suspend / hibernation is that long term we may be able to eventually drop the kernel's thread freezing completely as it was originally added to stop disk IO in flight as we hibernate or suspend. This does not remove the superfluous freezer calls on all filesystems. Each filesystem must remove all the kthread freezer stuff and peg the fs_type flags as supporting auto-freezing with the FS_AUTOFREEZE flag. Subsequent patches remove the kthread freezer usage from each filesystem, one at a time to make all this work bisectable. Once all filesystems remove the usage of the kthread freezer we can remove the FS_AUTOFREEZE flag. Reviewed-by: Jan Kara Signed-off-by: Luis Chamberlain --- fs/super.c | 50 ++++++++++++++++++++++++++++++++++++++++++ include/linux/fs.h | 14 ++++++++++++ kernel/power/process.c | 15 ++++++++++++- 3 files changed, 78 insertions(+), 1 deletion(-) diff --git a/fs/super.c b/fs/super.c index d5eab6b38b03..148674429ab8 100644 --- a/fs/super.c +++ b/fs/super.c @@ -1910,3 +1910,53 @@ int sb_init_dio_done_wq(struct super_block *sb) destroy_workqueue(wq); return 0; } + +#ifdef CONFIG_PM_SLEEP +static bool super_should_freeze(struct super_block *sb) +{ + if (!(sb->s_type->fs_flags & FS_AUTOFREEZE)) + return false; + /* + * We don't freeze virtual filesystems, we skip those filesystems with + * no backing device. + */ + if (sb->s_bdi =3D=3D &noop_backing_dev_info) + return false; + + return true; +} + +int fs_suspend_freeze_sb(struct super_block *sb, void *priv) +{ + int error =3D 0; + + if (!super_should_freeze(sb)) + goto out; + + pr_info("%s (%s): freezing\n", sb->s_type->name, sb->s_id); + + error =3D freeze_super(sb, false); + if (error && error !=3D -EBUSY) + pr_notice("%s (%s): Unable to freeze, error=3D%d", + sb->s_type->name, sb->s_id, error); +out: + return error; +} + +int fs_suspend_thaw_sb(struct super_block *sb, void *priv) +{ + int error =3D 0; + + if (!super_should_freeze(sb)) + goto out; + + pr_info("%s (%s): thawing\n", sb->s_type->name, sb->s_id); + + error =3D thaw_super(sb, false); + if (error && error !=3D -EBUSY) + pr_notice("%s (%s): Unable to unfreeze, error=3D%d", + sb->s_type->name, sb->s_id, error); +out: + return error; +} +#endif /* CONFIG_PM_SLEEP */ diff --git a/include/linux/fs.h b/include/linux/fs.h index 22dd697ab703..92c85c8ec1ed 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -2247,6 +2247,7 @@ struct file_system_type { #define FS_DISALLOW_NOTIFY_PERM 16 /* Disable fanotify permission events */ #define FS_ALLOW_IDMAP 32 /* FS has been updated to handle vf= s idmappings. */ #define FS_RENAME_DOES_D_MOVE 32768 /* FS will handle d_move() during rena= me() internally. */ +#define FS_AUTOFREEZE (1<<16) /* temporary as we phase kthread = freezer out */ int (*init_fs_context)(struct fs_context *); const struct fs_parameter_spec *parameters; struct dentry *(*mount) (struct file_system_type *, int, @@ -2322,6 +2323,19 @@ extern int user_statfs(const char __user *, struct k= statfs *); extern int fd_statfs(int, struct kstatfs *); extern int freeze_super(struct super_block *super, bool usercall); extern int thaw_super(struct super_block *super, bool usercall); +#ifdef CONFIG_PM_SLEEP +int fs_suspend_freeze_sb(struct super_block *sb, void *priv); +int fs_suspend_thaw_sb(struct super_block *sb, void *priv); +#else +static inline int fs_suspend_freeze_sb(struct super_block *sb, void *priv) +{ + return 0; +} +static inline int fs_suspend_thaw_sb(struct super_block *sb, void *priv) +{ + return 0; +} +#endif extern __printf(2, 3) int super_setup_bdi_name(struct super_block *sb, char *fmt, ...); extern int super_setup_bdi(struct super_block *sb); diff --git a/kernel/power/process.c b/kernel/power/process.c index cae81a87cc91..7ca7688f0b5d 100644 --- a/kernel/power/process.c +++ b/kernel/power/process.c @@ -140,6 +140,16 @@ int freeze_processes(void) =20 BUG_ON(in_atomic()); =20 + pr_info("Freezing filesystems ... "); + error =3D iterate_supers_reverse_excl(fs_suspend_freeze_sb, NULL); + if (error) { + pr_cont("failed\n"); + iterate_supers_excl(fs_suspend_thaw_sb, NULL); + thaw_processes(); + return error; + } + pr_cont("done.\n"); + /* * Now that the whole userspace is frozen we need to disable * the OOM killer to disallow any further interference with @@ -149,8 +159,10 @@ int freeze_processes(void) if (!error && !oom_killer_disable(msecs_to_jiffies(freeze_timeout_msecs))) error =3D -EBUSY; =20 - if (error) + if (error) { + iterate_supers_excl(fs_suspend_thaw_sb, NULL); thaw_processes(); + } return error; } =20 @@ -188,6 +200,7 @@ void thaw_processes(void) pm_nosig_freezing =3D false; =20 oom_killer_enable(); + iterate_supers_excl(fs_suspend_thaw_sb, NULL); =20 pr_info("Restarting tasks ... "); =20 --=20 2.39.2