From: "Darrick J. Wong" <djwong@kernel.org>
To: Luis Chamberlain <mcgrof@kernel.org>
Cc: hch@infradead.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, 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
Subject: Re: [PATCH 3/6] fs: distinguish between user initiated freeze and kernel initiated freeze
Date: Mon, 22 May 2023 16:42:00 -0700 [thread overview]
Message-ID: <20230522234200.GC11598@frogsfrogsfrogs> (raw)
In-Reply-To: <20230508011717.4034511-4-mcgrof@kernel.org>
How about this as an alternative patch? Kernel and userspace freeze
state are stored in s_writers; each type cannot block the other (though
you still can't have nested kernel or userspace freezes); and the freeze
is maintained until /both/ freeze types are dropped.
AFAICT this should work for the two other usecases (quiescing pagefaults
for fsdax pmem pre-removal; and freezing fses during suspend) besides
online fsck for xfs.
--D
From: Darrick J. Wong <djwong@kernel.org>
Subject: fs: distinguish between user initiated freeze and kernel initiated freeze
Userspace can freeze a filesystem using the FIFREEZE ioctl or by
suspending the block device; this state persists until userspace thaws
the filesystem with the FITHAW ioctl or resuming the block device.
Since commit 18e9e5104fcd ("Introduce freeze_super and thaw_super for
the fsfreeze ioctl") we only allow the first freeze command to succeed.
The kernel may decide that it is necessary to freeze a filesystem for
its own internal purposes, such as suspends in progress, filesystem fsck
activities, or quiescing a device prior to removal. Userspace thaw
commands must never break a kernel freeze, and kernel thaw commands
shouldn't undo userspace's freeze command.
Introduce a couple of freeze holder flags and wire it into the
sb_writers state. One kernel and one userspace freeze are allowed to
coexist at the same time; the filesystem will not thaw until both are
lifted.
Inspired-by: Luis Chamberlain <mcgrof@kernel.org>
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
fs/super.c | 172 +++++++++++++++++++++++++++++++++++++++++++++++++---
include/linux/fs.h | 8 ++
2 files changed, 170 insertions(+), 10 deletions(-)
diff --git a/fs/super.c b/fs/super.c
index 34afe411cf2b..7496d51affb9 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -39,7 +39,7 @@
#include <uapi/linux/mount.h>
#include "internal.h"
-static int thaw_super_locked(struct super_block *sb);
+static int thaw_super_locked(struct super_block *sb, unsigned short who);
static LIST_HEAD(super_blocks);
static DEFINE_SPINLOCK(sb_lock);
@@ -1027,7 +1027,7 @@ static void do_thaw_all_callback(struct super_block *sb)
down_write(&sb->s_umount);
if (sb->s_root && sb->s_flags & SB_BORN) {
emergency_thaw_bdev(sb);
- thaw_super_locked(sb);
+ thaw_super_locked(sb, FREEZE_HOLDER_USERSPACE);
} else {
up_write(&sb->s_umount);
}
@@ -1636,13 +1636,21 @@ static void sb_freeze_unlock(struct super_block *sb, int level)
}
/**
- * freeze_super - lock the filesystem and force it into a consistent state
+ * __freeze_super - lock the filesystem and force it into a consistent state
* @sb: the super to lock
+ * @who: FREEZE_HOLDER_USERSPACE if userspace wants to freeze the fs;
+ * FREEZE_HOLDER_KERNEL if the kernel wants to freeze it
*
* Syncs the super to make sure the filesystem is consistent and calls the fs's
- * freeze_fs. Subsequent calls to this without first thawing the fs will return
+ * freeze_fs. Subsequent calls to this without first thawing the fs may return
* -EBUSY.
*
+ * The @who argument distinguishes between the kernel and userspace trying to
+ * freeze the filesystem. Although there cannot be multiple kernel freezes or
+ * multiple userspace freezes in effect at any given time, the kernel and
+ * userspace can both hold a filesystem frozen. The filesystem remains frozen
+ * until there are no kernel or userspace freezes in effect.
+ *
* During this function, sb->s_writers.frozen goes through these values:
*
* SB_UNFROZEN: File system is normal, all writes progress as usual.
@@ -1668,12 +1676,61 @@ 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)
+static int __freeze_super(struct super_block *sb, unsigned short who)
{
+ struct sb_writers *sbw = &sb->s_writers;
int ret;
atomic_inc(&sb->s_active);
down_write(&sb->s_umount);
+
+ if (sbw->frozen == SB_FREEZE_COMPLETE) {
+ switch (who) {
+ case FREEZE_HOLDER_KERNEL:
+ if (sbw->freeze_holders & FREEZE_HOLDER_KERNEL) {
+ /*
+ * Kernel freeze already in effect; caller can
+ * try again.
+ */
+ deactivate_locked_super(sb);
+ return -EBUSY;
+ }
+ if (sbw->freeze_holders & FREEZE_HOLDER_USERSPACE) {
+ /*
+ * Share the freeze state with the userspace
+ * freeze already in effect.
+ */
+ sbw->freeze_holders |= who;
+ deactivate_locked_super(sb);
+ return 0;
+ }
+ break;
+ case FREEZE_HOLDER_USERSPACE:
+ if (sbw->freeze_holders & FREEZE_HOLDER_USERSPACE) {
+ /*
+ * Userspace freeze already in effect; tell
+ * the caller we're busy.
+ */
+ deactivate_locked_super(sb);
+ return -EBUSY;
+ }
+ if (sbw->freeze_holders & FREEZE_HOLDER_KERNEL) {
+ /*
+ * Share the freeze state with the kernel
+ * freeze already in effect.
+ */
+ sbw->freeze_holders |= who;
+ deactivate_locked_super(sb);
+ return 0;
+ }
+ break;
+ default:
+ BUG();
+ deactivate_locked_super(sb);
+ return -EINVAL;
+ }
+ }
+
if (sb->s_writers.frozen != SB_UNFROZEN) {
deactivate_locked_super(sb);
return -EBUSY;
@@ -1686,6 +1743,7 @@ int freeze_super(struct super_block *sb)
if (sb_rdonly(sb)) {
/* Nothing to do really... */
+ sb->s_writers.freeze_holders |= who;
sb->s_writers.frozen = SB_FREEZE_COMPLETE;
up_write(&sb->s_umount);
return 0;
@@ -1731,23 +1789,103 @@ int freeze_super(struct super_block *sb)
* For debugging purposes so that fs can warn if it sees write activity
* when frozen is set to SB_FREEZE_COMPLETE, and for thaw_super().
*/
+ sb->s_writers.freeze_holders |= who;
sb->s_writers.frozen = SB_FREEZE_COMPLETE;
lockdep_sb_freeze_release(sb);
up_write(&sb->s_umount);
return 0;
}
+
+/*
+ * freeze_super - lock the filesystem and force it into a consistent state
+ * @sb: the super to lock
+ *
+ * Syncs the super to make sure the filesystem is consistent and calls the fs's
+ * freeze_fs. Subsequent calls to this without first calling thaw_super will
+ * return -EBUSY. See the comment for __freeze_super for more information.
+ */
+int freeze_super(struct super_block *sb)
+{
+ return __freeze_super(sb, FREEZE_HOLDER_USERSPACE);
+}
EXPORT_SYMBOL(freeze_super);
-static int thaw_super_locked(struct super_block *sb)
+/**
+ * freeze_super_kernel - lock the filesystem for an internal kernel operation
+ * and force it into a consistent state.
+ * @sb: the super to lock
+ *
+ * Syncs the super to make sure the filesystem is consistent and calls the fs's
+ * freeze_fs. Subsequent calls to this without first calling thaw_super_excl
+ * will return -EBUSY.
+ */
+int freeze_super_kernel(struct super_block *sb)
{
+ return __freeze_super(sb, FREEZE_HOLDER_KERNEL);
+}
+EXPORT_SYMBOL_GPL(freeze_super_kernel);
+
+/*
+ * Undoes the effect of a freeze_super_locked call. If the filesystem is
+ * frozen both by userspace and the kernel, a thaw call from either source
+ * removes that state without releasing the other state or unlocking the
+ * filesystem.
+ */
+static int thaw_super_locked(struct super_block *sb, unsigned short who)
+{
+ struct sb_writers *sbw = &sb->s_writers;
int error;
+ if (sbw->frozen == SB_FREEZE_COMPLETE) {
+ switch (who) {
+ case FREEZE_HOLDER_KERNEL:
+ if (!(sbw->freeze_holders & FREEZE_HOLDER_KERNEL)) {
+ /* Caller doesn't hold a kernel freeze. */
+ up_write(&sb->s_umount);
+ return -EINVAL;
+ }
+ if (sbw->freeze_holders & FREEZE_HOLDER_USERSPACE) {
+ /*
+ * We were sharing the freeze with userspace,
+ * so drop the userspace freeze but exit
+ * without unfreezing.
+ */
+ sbw->freeze_holders &= ~who;
+ up_write(&sb->s_umount);
+ return 0;
+ }
+ break;
+ case FREEZE_HOLDER_USERSPACE:
+ if (!(sbw->freeze_holders & FREEZE_HOLDER_USERSPACE)) {
+ /* Caller doesn't hold a userspace freeze. */
+ up_write(&sb->s_umount);
+ return -EINVAL;
+ }
+ if (sbw->freeze_holders & FREEZE_HOLDER_KERNEL) {
+ /*
+ * We were sharing the freeze with the kernel,
+ * so drop the kernel freeze but exit without
+ * unfreezing.
+ */
+ sbw->freeze_holders &= ~who;
+ up_write(&sb->s_umount);
+ return 0;
+ }
+ break;
+ default:
+ BUG();
+ up_write(&sb->s_umount);
+ return -EINVAL;
+ }
+ }
+
if (sb->s_writers.frozen != SB_FREEZE_COMPLETE) {
up_write(&sb->s_umount);
return -EINVAL;
}
if (sb_rdonly(sb)) {
+ sb->s_writers.freeze_holders &= ~who;
sb->s_writers.frozen = SB_UNFROZEN;
goto out;
}
@@ -1765,6 +1903,7 @@ static int thaw_super_locked(struct super_block *sb)
}
}
+ sb->s_writers.freeze_holders &= ~who;
sb->s_writers.frozen = SB_UNFROZEN;
sb_freeze_unlock(sb, SB_FREEZE_FS);
out:
@@ -1774,18 +1913,33 @@ static int thaw_super_locked(struct super_block *sb)
}
/**
- * thaw_super -- unlock filesystem
+ * thaw_super -- unlock filesystem frozen with freeze_super
* @sb: the super to thaw
*
- * Unlocks the filesystem and marks it writeable again after freeze_super().
+ * Unlocks the filesystem after freeze_super, and make it writeable again if
+ * there is not a freeze_super_kernel still in effect.
*/
int thaw_super(struct super_block *sb)
{
down_write(&sb->s_umount);
- return thaw_super_locked(sb);
+ return thaw_super_locked(sb, FREEZE_HOLDER_USERSPACE);
}
EXPORT_SYMBOL(thaw_super);
+/**
+ * thaw_super_kernel -- unlock filesystem frozen with freeze_super_kernel
+ * @sb: the super to thaw
+ *
+ * Unlocks the filesystem after freeze_super_kernel, and make it writeable
+ * again if there is not a freeze_super still in effect.
+ */
+int thaw_super_kernel(struct super_block *sb)
+{
+ down_write(&sb->s_umount);
+ return thaw_super_locked(sb, FREEZE_HOLDER_KERNEL);
+}
+EXPORT_SYMBOL_GPL(thaw_super_kernel);
+
/*
* Create workqueue for deferred direct IO completions. We allocate the
* workqueue when it's first needed. This avoids creating workqueue for
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 21a981680856..147644b5d648 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1145,11 +1145,15 @@ enum {
#define SB_FREEZE_LEVELS (SB_FREEZE_COMPLETE - 1)
struct sb_writers {
- int frozen; /* Is sb frozen? */
+ unsigned short frozen; /* Is sb frozen? */
+ unsigned short freeze_holders; /* Who froze fs? */
wait_queue_head_t wait_unfrozen; /* wait for thaw */
struct percpu_rw_semaphore rw_sem[SB_FREEZE_LEVELS];
};
+#define FREEZE_HOLDER_USERSPACE (1U << 1) /* userspace froze fs */
+#define FREEZE_HOLDER_KERNEL (1U << 2) /* kernel froze fs */
+
struct super_block {
struct list_head s_list; /* Keep this first */
dev_t s_dev; /* search index; _not_ kdev_t */
@@ -2288,6 +2292,8 @@ 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_kernel(struct super_block *super);
+extern int thaw_super_kernel(struct super_block *super);
extern __printf(2, 3)
int super_setup_bdi_name(struct super_block *sb, char *fmt, ...);
extern int super_setup_bdi(struct super_block *sb);
_______________________________________________
kexec mailing list
kexec@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/kexec
WARNING: multiple messages have this Message-ID (diff)
From: "Darrick J. Wong" <djwong@kernel.org>
To: Luis Chamberlain <mcgrof@kernel.org>
Cc: hch@infradead.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, 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
Subject: Re: [PATCH 3/6] fs: distinguish between user initiated freeze and kernel initiated freeze
Date: Mon, 22 May 2023 16:42:00 -0700 [thread overview]
Message-ID: <20230522234200.GC11598@frogsfrogsfrogs> (raw)
In-Reply-To: <20230508011717.4034511-4-mcgrof@kernel.org>
How about this as an alternative patch? Kernel and userspace freeze
state are stored in s_writers; each type cannot block the other (though
you still can't have nested kernel or userspace freezes); and the freeze
is maintained until /both/ freeze types are dropped.
AFAICT this should work for the two other usecases (quiescing pagefaults
for fsdax pmem pre-removal; and freezing fses during suspend) besides
online fsck for xfs.
--D
From: Darrick J. Wong <djwong@kernel.org>
Subject: fs: distinguish between user initiated freeze and kernel initiated freeze
Userspace can freeze a filesystem using the FIFREEZE ioctl or by
suspending the block device; this state persists until userspace thaws
the filesystem with the FITHAW ioctl or resuming the block device.
Since commit 18e9e5104fcd ("Introduce freeze_super and thaw_super for
the fsfreeze ioctl") we only allow the first freeze command to succeed.
The kernel may decide that it is necessary to freeze a filesystem for
its own internal purposes, such as suspends in progress, filesystem fsck
activities, or quiescing a device prior to removal. Userspace thaw
commands must never break a kernel freeze, and kernel thaw commands
shouldn't undo userspace's freeze command.
Introduce a couple of freeze holder flags and wire it into the
sb_writers state. One kernel and one userspace freeze are allowed to
coexist at the same time; the filesystem will not thaw until both are
lifted.
Inspired-by: Luis Chamberlain <mcgrof@kernel.org>
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
fs/super.c | 172 +++++++++++++++++++++++++++++++++++++++++++++++++---
include/linux/fs.h | 8 ++
2 files changed, 170 insertions(+), 10 deletions(-)
diff --git a/fs/super.c b/fs/super.c
index 34afe411cf2b..7496d51affb9 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -39,7 +39,7 @@
#include <uapi/linux/mount.h>
#include "internal.h"
-static int thaw_super_locked(struct super_block *sb);
+static int thaw_super_locked(struct super_block *sb, unsigned short who);
static LIST_HEAD(super_blocks);
static DEFINE_SPINLOCK(sb_lock);
@@ -1027,7 +1027,7 @@ static void do_thaw_all_callback(struct super_block *sb)
down_write(&sb->s_umount);
if (sb->s_root && sb->s_flags & SB_BORN) {
emergency_thaw_bdev(sb);
- thaw_super_locked(sb);
+ thaw_super_locked(sb, FREEZE_HOLDER_USERSPACE);
} else {
up_write(&sb->s_umount);
}
@@ -1636,13 +1636,21 @@ static void sb_freeze_unlock(struct super_block *sb, int level)
}
/**
- * freeze_super - lock the filesystem and force it into a consistent state
+ * __freeze_super - lock the filesystem and force it into a consistent state
* @sb: the super to lock
+ * @who: FREEZE_HOLDER_USERSPACE if userspace wants to freeze the fs;
+ * FREEZE_HOLDER_KERNEL if the kernel wants to freeze it
*
* Syncs the super to make sure the filesystem is consistent and calls the fs's
- * freeze_fs. Subsequent calls to this without first thawing the fs will return
+ * freeze_fs. Subsequent calls to this without first thawing the fs may return
* -EBUSY.
*
+ * The @who argument distinguishes between the kernel and userspace trying to
+ * freeze the filesystem. Although there cannot be multiple kernel freezes or
+ * multiple userspace freezes in effect at any given time, the kernel and
+ * userspace can both hold a filesystem frozen. The filesystem remains frozen
+ * until there are no kernel or userspace freezes in effect.
+ *
* During this function, sb->s_writers.frozen goes through these values:
*
* SB_UNFROZEN: File system is normal, all writes progress as usual.
@@ -1668,12 +1676,61 @@ 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)
+static int __freeze_super(struct super_block *sb, unsigned short who)
{
+ struct sb_writers *sbw = &sb->s_writers;
int ret;
atomic_inc(&sb->s_active);
down_write(&sb->s_umount);
+
+ if (sbw->frozen == SB_FREEZE_COMPLETE) {
+ switch (who) {
+ case FREEZE_HOLDER_KERNEL:
+ if (sbw->freeze_holders & FREEZE_HOLDER_KERNEL) {
+ /*
+ * Kernel freeze already in effect; caller can
+ * try again.
+ */
+ deactivate_locked_super(sb);
+ return -EBUSY;
+ }
+ if (sbw->freeze_holders & FREEZE_HOLDER_USERSPACE) {
+ /*
+ * Share the freeze state with the userspace
+ * freeze already in effect.
+ */
+ sbw->freeze_holders |= who;
+ deactivate_locked_super(sb);
+ return 0;
+ }
+ break;
+ case FREEZE_HOLDER_USERSPACE:
+ if (sbw->freeze_holders & FREEZE_HOLDER_USERSPACE) {
+ /*
+ * Userspace freeze already in effect; tell
+ * the caller we're busy.
+ */
+ deactivate_locked_super(sb);
+ return -EBUSY;
+ }
+ if (sbw->freeze_holders & FREEZE_HOLDER_KERNEL) {
+ /*
+ * Share the freeze state with the kernel
+ * freeze already in effect.
+ */
+ sbw->freeze_holders |= who;
+ deactivate_locked_super(sb);
+ return 0;
+ }
+ break;
+ default:
+ BUG();
+ deactivate_locked_super(sb);
+ return -EINVAL;
+ }
+ }
+
if (sb->s_writers.frozen != SB_UNFROZEN) {
deactivate_locked_super(sb);
return -EBUSY;
@@ -1686,6 +1743,7 @@ int freeze_super(struct super_block *sb)
if (sb_rdonly(sb)) {
/* Nothing to do really... */
+ sb->s_writers.freeze_holders |= who;
sb->s_writers.frozen = SB_FREEZE_COMPLETE;
up_write(&sb->s_umount);
return 0;
@@ -1731,23 +1789,103 @@ int freeze_super(struct super_block *sb)
* For debugging purposes so that fs can warn if it sees write activity
* when frozen is set to SB_FREEZE_COMPLETE, and for thaw_super().
*/
+ sb->s_writers.freeze_holders |= who;
sb->s_writers.frozen = SB_FREEZE_COMPLETE;
lockdep_sb_freeze_release(sb);
up_write(&sb->s_umount);
return 0;
}
+
+/*
+ * freeze_super - lock the filesystem and force it into a consistent state
+ * @sb: the super to lock
+ *
+ * Syncs the super to make sure the filesystem is consistent and calls the fs's
+ * freeze_fs. Subsequent calls to this without first calling thaw_super will
+ * return -EBUSY. See the comment for __freeze_super for more information.
+ */
+int freeze_super(struct super_block *sb)
+{
+ return __freeze_super(sb, FREEZE_HOLDER_USERSPACE);
+}
EXPORT_SYMBOL(freeze_super);
-static int thaw_super_locked(struct super_block *sb)
+/**
+ * freeze_super_kernel - lock the filesystem for an internal kernel operation
+ * and force it into a consistent state.
+ * @sb: the super to lock
+ *
+ * Syncs the super to make sure the filesystem is consistent and calls the fs's
+ * freeze_fs. Subsequent calls to this without first calling thaw_super_excl
+ * will return -EBUSY.
+ */
+int freeze_super_kernel(struct super_block *sb)
{
+ return __freeze_super(sb, FREEZE_HOLDER_KERNEL);
+}
+EXPORT_SYMBOL_GPL(freeze_super_kernel);
+
+/*
+ * Undoes the effect of a freeze_super_locked call. If the filesystem is
+ * frozen both by userspace and the kernel, a thaw call from either source
+ * removes that state without releasing the other state or unlocking the
+ * filesystem.
+ */
+static int thaw_super_locked(struct super_block *sb, unsigned short who)
+{
+ struct sb_writers *sbw = &sb->s_writers;
int error;
+ if (sbw->frozen == SB_FREEZE_COMPLETE) {
+ switch (who) {
+ case FREEZE_HOLDER_KERNEL:
+ if (!(sbw->freeze_holders & FREEZE_HOLDER_KERNEL)) {
+ /* Caller doesn't hold a kernel freeze. */
+ up_write(&sb->s_umount);
+ return -EINVAL;
+ }
+ if (sbw->freeze_holders & FREEZE_HOLDER_USERSPACE) {
+ /*
+ * We were sharing the freeze with userspace,
+ * so drop the userspace freeze but exit
+ * without unfreezing.
+ */
+ sbw->freeze_holders &= ~who;
+ up_write(&sb->s_umount);
+ return 0;
+ }
+ break;
+ case FREEZE_HOLDER_USERSPACE:
+ if (!(sbw->freeze_holders & FREEZE_HOLDER_USERSPACE)) {
+ /* Caller doesn't hold a userspace freeze. */
+ up_write(&sb->s_umount);
+ return -EINVAL;
+ }
+ if (sbw->freeze_holders & FREEZE_HOLDER_KERNEL) {
+ /*
+ * We were sharing the freeze with the kernel,
+ * so drop the kernel freeze but exit without
+ * unfreezing.
+ */
+ sbw->freeze_holders &= ~who;
+ up_write(&sb->s_umount);
+ return 0;
+ }
+ break;
+ default:
+ BUG();
+ up_write(&sb->s_umount);
+ return -EINVAL;
+ }
+ }
+
if (sb->s_writers.frozen != SB_FREEZE_COMPLETE) {
up_write(&sb->s_umount);
return -EINVAL;
}
if (sb_rdonly(sb)) {
+ sb->s_writers.freeze_holders &= ~who;
sb->s_writers.frozen = SB_UNFROZEN;
goto out;
}
@@ -1765,6 +1903,7 @@ static int thaw_super_locked(struct super_block *sb)
}
}
+ sb->s_writers.freeze_holders &= ~who;
sb->s_writers.frozen = SB_UNFROZEN;
sb_freeze_unlock(sb, SB_FREEZE_FS);
out:
@@ -1774,18 +1913,33 @@ static int thaw_super_locked(struct super_block *sb)
}
/**
- * thaw_super -- unlock filesystem
+ * thaw_super -- unlock filesystem frozen with freeze_super
* @sb: the super to thaw
*
- * Unlocks the filesystem and marks it writeable again after freeze_super().
+ * Unlocks the filesystem after freeze_super, and make it writeable again if
+ * there is not a freeze_super_kernel still in effect.
*/
int thaw_super(struct super_block *sb)
{
down_write(&sb->s_umount);
- return thaw_super_locked(sb);
+ return thaw_super_locked(sb, FREEZE_HOLDER_USERSPACE);
}
EXPORT_SYMBOL(thaw_super);
+/**
+ * thaw_super_kernel -- unlock filesystem frozen with freeze_super_kernel
+ * @sb: the super to thaw
+ *
+ * Unlocks the filesystem after freeze_super_kernel, and make it writeable
+ * again if there is not a freeze_super still in effect.
+ */
+int thaw_super_kernel(struct super_block *sb)
+{
+ down_write(&sb->s_umount);
+ return thaw_super_locked(sb, FREEZE_HOLDER_KERNEL);
+}
+EXPORT_SYMBOL_GPL(thaw_super_kernel);
+
/*
* Create workqueue for deferred direct IO completions. We allocate the
* workqueue when it's first needed. This avoids creating workqueue for
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 21a981680856..147644b5d648 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1145,11 +1145,15 @@ enum {
#define SB_FREEZE_LEVELS (SB_FREEZE_COMPLETE - 1)
struct sb_writers {
- int frozen; /* Is sb frozen? */
+ unsigned short frozen; /* Is sb frozen? */
+ unsigned short freeze_holders; /* Who froze fs? */
wait_queue_head_t wait_unfrozen; /* wait for thaw */
struct percpu_rw_semaphore rw_sem[SB_FREEZE_LEVELS];
};
+#define FREEZE_HOLDER_USERSPACE (1U << 1) /* userspace froze fs */
+#define FREEZE_HOLDER_KERNEL (1U << 2) /* kernel froze fs */
+
struct super_block {
struct list_head s_list; /* Keep this first */
dev_t s_dev; /* search index; _not_ kdev_t */
@@ -2288,6 +2292,8 @@ 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_kernel(struct super_block *super);
+extern int thaw_super_kernel(struct super_block *super);
extern __printf(2, 3)
int super_setup_bdi_name(struct super_block *sb, char *fmt, ...);
extern int super_setup_bdi(struct super_block *sb);
next prev parent reply other threads:[~2023-05-22 23:42 UTC|newest]
Thread overview: 70+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-05-08 1:17 [PATCH 0/6] vfs: provide automatic kernel freeze / resume Luis Chamberlain
2023-05-08 1:17 ` Luis Chamberlain
2023-05-08 1:17 ` [PATCH 1/6] fs: unify locking semantics for fs freeze / thaw Luis Chamberlain
2023-05-08 1:17 ` Luis Chamberlain
2023-05-12 6:00 ` kernel test robot
2023-05-12 23:54 ` kernel test robot
2023-05-18 5:32 ` Darrick J. Wong
2023-05-18 5:32 ` Darrick J. Wong
2023-05-25 12:17 ` Jan Kara
2023-05-25 12:17 ` Jan Kara
2023-06-08 5:01 ` Christoph Hellwig
2023-06-08 5:01 ` Christoph Hellwig
2023-06-08 19:55 ` Luis Chamberlain
2023-06-08 19:55 ` Luis Chamberlain
2023-05-08 1:17 ` [PATCH 2/6] fs: add frozen sb state helpers Luis Chamberlain
2023-05-08 1:17 ` Luis Chamberlain
2023-05-25 12:19 ` Jan Kara
2023-05-25 12:19 ` Jan Kara
2023-06-08 5:05 ` Christoph Hellwig
2023-06-08 5:05 ` Christoph Hellwig
2023-06-08 15:05 ` Darrick J. Wong
2023-06-08 15:05 ` Darrick J. Wong
2023-05-08 1:17 ` [PATCH 3/6] fs: distinguish between user initiated freeze and kernel initiated freeze Luis Chamberlain
2023-05-08 1:17 ` Luis Chamberlain
2023-05-16 15:23 ` Darrick J. Wong
2023-05-16 15:23 ` Darrick J. Wong
2023-05-22 23:42 ` Darrick J. Wong [this message]
2023-05-22 23:42 ` Darrick J. Wong
2023-05-25 14:14 ` Jan Kara
2023-05-25 14:14 ` Jan Kara
2023-06-06 17:19 ` Darrick J. Wong
2023-06-06 17:19 ` Darrick J. Wong
2023-06-07 9:22 ` Jan Kara
2023-06-07 9:22 ` Jan Kara
2023-06-07 14:50 ` Darrick J. Wong
2023-06-07 14:50 ` Darrick J. Wong
2023-06-08 20:30 ` Luis Chamberlain
2023-06-08 20:30 ` Luis Chamberlain
2023-06-07 16:31 ` Darrick J. Wong
2023-06-07 16:31 ` Darrick J. Wong
2023-06-07 20:46 ` Jan Kara
2023-06-07 20:46 ` Jan Kara
2023-06-08 18:58 ` Darrick J. Wong
2023-06-08 18:58 ` Darrick J. Wong
2023-06-08 5:29 ` Christoph Hellwig
2023-06-08 5:29 ` Christoph Hellwig
2023-06-08 9:11 ` Jan Kara
2023-06-08 9:11 ` Jan Kara
2023-06-08 18:16 ` Darrick J. Wong
2023-06-08 18:16 ` Darrick J. Wong
2023-06-08 5:24 ` Christoph Hellwig
2023-06-08 5:24 ` Christoph Hellwig
2023-06-08 18:15 ` Darrick J. Wong
2023-06-08 18:15 ` Darrick J. Wong
2023-06-08 20:26 ` Luis Chamberlain
2023-06-08 20:26 ` Luis Chamberlain
2023-06-08 21:10 ` Darrick J. Wong
2023-06-08 21:10 ` Darrick J. Wong
2023-05-08 1:17 ` [PATCH 4/6] fs: move !SB_BORN check early on freeze and add for thaw Luis Chamberlain
2023-05-08 1:17 ` Luis Chamberlain
2023-05-08 1:17 ` [PATCH 5/6] fs: add iterate_supers_excl() and iterate_supers_reverse_excl() Luis Chamberlain
2023-05-08 1:17 ` Luis Chamberlain
2023-05-08 1:17 ` [PATCH 6/6] fs: add automatic kernel fs freeze / thaw and remove kthread freezing Luis Chamberlain
2023-05-08 1:17 ` Luis Chamberlain
2023-05-09 1:20 ` Dave Chinner
2023-05-09 1:20 ` Dave Chinner
2023-05-16 15:17 ` Darrick J. Wong
2023-05-16 15:17 ` Darrick J. Wong
2023-05-08 1:21 ` [PATCH 0/6] vfs: provide automatic kernel freeze / resume Luis Chamberlain
2023-05-08 1:21 ` Luis Chamberlain
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20230522234200.GC11598@frogsfrogsfrogs \
--to=djwong@kernel.org \
--cc=bvanassche@acm.org \
--cc=da.gomez@samsung.com \
--cc=ebiederm@xmission.com \
--cc=gregkh@linuxfoundation.org \
--cc=hch@infradead.org \
--cc=jack@suse.cz \
--cc=jikos@kernel.org \
--cc=keescook@chromium.org \
--cc=kernel@tuxforce.de \
--cc=kexec@lists.infradead.org \
--cc=linux-fsdevel@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=mcgrof@kernel.org \
--cc=mchehab@kernel.org \
--cc=p.raghav@samsung.com \
--cc=rafael@kernel.org \
--cc=sandeen@sandeen.net \
--cc=song@kernel.org \
--cc=viro@zeniv.linux.org.uk \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.