From: Christian Brauner <brauner@kernel.org>
To: linux-fsdevel@vger.kernel.org, jack@suse.cz,
Ard Biesheuvel <ardb@kernel.org>
Cc: Christian Brauner <brauner@kernel.org>,
linux-efi@vger.kernel.org, linux-kernel@vger.kernel.org,
James Bottomley <James.Bottomley@hansenpartnership.com>,
mcgrof@kernel.org, hch@infradead.org, david@fromorbit.com,
rafael@kernel.org, djwong@kernel.org, pavel@kernel.org,
peterz@infradead.org, mingo@redhat.com, will@kernel.org,
boqun.feng@gmail.com
Subject: [PATCH 2/2] efivarfs: support freeze/thaw
Date: Mon, 31 Mar 2025 14:42:12 +0200 [thread overview]
Message-ID: <20250331-work-freeze-v1-2-6dfbe8253b9f@kernel.org> (raw)
In-Reply-To: <20250331-work-freeze-v1-0-6dfbe8253b9f@kernel.org>
Allow efivarfs to partake to resync variable state during system
hibernation and suspend. Add freeze/thaw support.
This is a pretty straightforward implementation. We simply add regular
freeze/thaw support for both userspace and the kernel. This works
without any big issues and congrats afaict efivars is the first
pseudofilesystem that adds support for filesystem freezing and thawing.
The simplicity comes from the fact that we simply always resync variable
state after efivarfs has been frozen. It doesn't matter whether that's
because of suspend, userspace initiated freeze or hibernation. Efivars
is simple enough that it doesn't matter that we walk all dentries. There
are no directories and there aren't insane amounts of entries and both
freeze/thaw are already heavy-handed operations. We really really don't
need to care.
Signed-off-by: Christian Brauner <brauner@kernel.org>
---
fs/efivarfs/internal.h | 1 -
fs/efivarfs/super.c | 196 +++++++++++++------------------------------------
2 files changed, 51 insertions(+), 146 deletions(-)
diff --git a/fs/efivarfs/internal.h b/fs/efivarfs/internal.h
index ac6a1dd0a6a5..f913b6824289 100644
--- a/fs/efivarfs/internal.h
+++ b/fs/efivarfs/internal.h
@@ -17,7 +17,6 @@ struct efivarfs_fs_info {
struct efivarfs_mount_opts mount_opts;
struct super_block *sb;
struct notifier_block nb;
- struct notifier_block pm_nb;
};
struct efi_variable {
diff --git a/fs/efivarfs/super.c b/fs/efivarfs/super.c
index 0486e9b68bc6..567e849a03fe 100644
--- a/fs/efivarfs/super.c
+++ b/fs/efivarfs/super.c
@@ -20,6 +20,7 @@
#include <linux/printk.h>
#include "internal.h"
+#include "../internal.h"
static int efivarfs_ops_notifier(struct notifier_block *nb, unsigned long event,
void *data)
@@ -119,12 +120,18 @@ static int efivarfs_statfs(struct dentry *dentry, struct kstatfs *buf)
return 0;
}
+
+static int efivarfs_freeze_fs(struct super_block *sb);
+static int efivarfs_unfreeze_fs(struct super_block *sb);
+
static const struct super_operations efivarfs_ops = {
.statfs = efivarfs_statfs,
.drop_inode = generic_delete_inode,
.alloc_inode = efivarfs_alloc_inode,
.free_inode = efivarfs_free_inode,
.show_options = efivarfs_show_options,
+ .freeze_fs = efivarfs_freeze_fs,
+ .unfreeze_fs = efivarfs_unfreeze_fs,
};
/*
@@ -367,8 +374,6 @@ static int efivarfs_fill_super(struct super_block *sb, struct fs_context *fc)
if (err)
return err;
- register_pm_notifier(&sfi->pm_nb);
-
return efivar_init(efivarfs_callback, sb, true);
}
@@ -393,48 +398,6 @@ static const struct fs_context_operations efivarfs_context_ops = {
.reconfigure = efivarfs_reconfigure,
};
-struct efivarfs_ctx {
- struct dir_context ctx;
- struct super_block *sb;
- struct dentry *dentry;
-};
-
-static bool efivarfs_actor(struct dir_context *ctx, const char *name, int len,
- loff_t offset, u64 ino, unsigned mode)
-{
- unsigned long size;
- struct efivarfs_ctx *ectx = container_of(ctx, struct efivarfs_ctx, ctx);
- struct qstr qstr = { .name = name, .len = len };
- struct dentry *dentry = d_hash_and_lookup(ectx->sb->s_root, &qstr);
- struct inode *inode;
- struct efivar_entry *entry;
- int err;
-
- if (IS_ERR_OR_NULL(dentry))
- return true;
-
- inode = d_inode(dentry);
- entry = efivar_entry(inode);
-
- err = efivar_entry_size(entry, &size);
- size += sizeof(__u32); /* attributes */
- if (err)
- size = 0;
-
- inode_lock_nested(inode, I_MUTEX_CHILD);
- i_size_write(inode, size);
- inode_unlock(inode);
-
- if (!size) {
- ectx->dentry = dentry;
- return false;
- }
-
- dput(dentry);
-
- return true;
-}
-
static int efivarfs_check_missing(efi_char16_t *name16, efi_guid_t vendor,
unsigned long name_size, void *data)
{
@@ -474,111 +437,59 @@ static int efivarfs_check_missing(efi_char16_t *name16, efi_guid_t vendor,
return err;
}
-static void efivarfs_deactivate_super_work(struct work_struct *work)
-{
- struct super_block *s = container_of(work, struct super_block,
- destroy_work);
- /*
- * note: here s->destroy_work is free for reuse (which
- * will happen in deactivate_super)
- */
- deactivate_super(s);
-}
-
static struct file_system_type efivarfs_type;
-static int efivarfs_pm_notify(struct notifier_block *nb, unsigned long action,
- void *ptr)
+static int efivarfs_freeze_fs(struct super_block *sb)
{
- struct efivarfs_fs_info *sfi = container_of(nb, struct efivarfs_fs_info,
- pm_nb);
- struct path path;
- struct efivarfs_ctx ectx = {
- .ctx = {
- .actor = efivarfs_actor,
- },
- .sb = sfi->sb,
- };
- struct file *file;
- struct super_block *s = sfi->sb;
- static bool rescan_done = true;
-
- if (action == PM_HIBERNATION_PREPARE) {
- rescan_done = false;
- return NOTIFY_OK;
- } else if (action != PM_POST_HIBERNATION) {
- return NOTIFY_DONE;
- }
-
- if (rescan_done)
- return NOTIFY_DONE;
-
- /* ensure single superblock is alive and pin it */
- if (!atomic_inc_not_zero(&s->s_active))
- return NOTIFY_DONE;
-
- pr_info("efivarfs: resyncing variable state\n");
+ /* Nothing for us to do. */
+ return 0;
+}
- path.dentry = sfi->sb->s_root;
+static int efivarfs_unfreeze_fs(struct super_block *sb)
+{
+ struct dentry *child = NULL;
/*
- * do not add SB_KERNMOUNT which a single superblock could
- * expose to userspace and which also causes MNT_INTERNAL, see
- * below
+ * Unconditionally resync the variable state on a thaw request.
+ * Given the size of efivarfs it really doesn't matter to simply
+ * iterate through all of the entries and resync. Freeze/thaw
+ * requests are rare enough for that to not matter and the
+ * number of entries is pretty low too. So we really don't care.
*/
- path.mnt = vfs_kern_mount(&efivarfs_type, 0,
- efivarfs_type.name, NULL);
- if (IS_ERR(path.mnt)) {
- pr_err("efivarfs: internal mount failed\n");
- /*
- * We may be the last pinner of the superblock but
- * calling efivarfs_kill_sb from within the notifier
- * here would deadlock trying to unregister it
- */
- INIT_WORK(&s->destroy_work, efivarfs_deactivate_super_work);
- schedule_work(&s->destroy_work);
- return PTR_ERR(path.mnt);
+ pr_info("efivarfs: resyncing variable state\n");
+ for (;;) {
+ int err;
+ size_t size;
+ struct inode *inode;
+ struct efivar_entry *entry;
+
+ child = find_next_child(sb->s_root, child);
+ if (!child)
+ break;
+
+ inode = d_inode(child);
+ entry = efivar_entry(inode);
+
+ err = efivar_entry_size(entry, &size);
+ if (err)
+ size = 0;
+ else
+ size += sizeof(__u32);
+
+ inode_lock(inode);
+ i_size_write(inode, size);
+ inode_unlock(inode);
+
+ if (!err)
+ continue;
+
+ /* The variable doesn't exist anymore, delete it. */
+ simple_recursive_removal(child, NULL);
}
- /* path.mnt now has pin on superblock, so this must be above one */
- atomic_dec(&s->s_active);
-
- file = kernel_file_open(&path, O_RDONLY | O_DIRECTORY | O_NOATIME,
- current_cred());
- /*
- * safe even if last put because no MNT_INTERNAL means this
- * will do delayed deactivate_super and not deadlock
- */
- mntput(path.mnt);
- if (IS_ERR(file))
- return NOTIFY_DONE;
-
- rescan_done = true;
-
- /*
- * First loop over the directory and verify each entry exists,
- * removing it if it doesn't
- */
- file->f_pos = 2; /* skip . and .. */
- do {
- ectx.dentry = NULL;
- iterate_dir(file, &ectx.ctx);
- if (ectx.dentry) {
- pr_info("efivarfs: removing variable %pd\n",
- ectx.dentry);
- simple_recursive_removal(ectx.dentry, NULL);
- dput(ectx.dentry);
- }
- } while (ectx.dentry);
- fput(file);
-
- /*
- * then loop over variables, creating them if there's no matching
- * dentry
- */
- efivar_init(efivarfs_check_missing, sfi->sb, false);
-
- return NOTIFY_OK;
+ efivar_init(efivarfs_check_missing, sb, false);
+ pr_info("efivarfs: finished resyncing variable state\n");
+ return 0;
}
static int efivarfs_init_fs_context(struct fs_context *fc)
@@ -598,9 +509,6 @@ static int efivarfs_init_fs_context(struct fs_context *fc)
fc->s_fs_info = sfi;
fc->ops = &efivarfs_context_ops;
- sfi->pm_nb.notifier_call = efivarfs_pm_notify;
- sfi->pm_nb.priority = 0;
-
return 0;
}
@@ -608,9 +516,7 @@ static void efivarfs_kill_sb(struct super_block *sb)
{
struct efivarfs_fs_info *sfi = sb->s_fs_info;
- blocking_notifier_chain_unregister(&efivar_ops_nh, &sfi->nb);
kill_litter_super(sb);
- unregister_pm_notifier(&sfi->pm_nb);
kfree(sfi);
}
--
2.47.2
next prev parent reply other threads:[~2025-03-31 12:42 UTC|newest]
Thread overview: 120+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-03-27 14:06 [RFC PATCH 0/4] vfs freeze/thaw on suspend/resume James Bottomley
2025-03-27 14:06 ` [RFC PATCH 1/4] locking/percpu-rwsem: add freezable alternative to down_read James Bottomley
2025-03-31 19:51 ` James Bottomley
2025-03-31 23:32 ` Christian Brauner
2025-04-01 1:13 ` James Bottomley
2025-04-01 11:20 ` Jan Kara
2025-04-01 12:50 ` Christian Brauner
2025-04-01 12:52 ` James Bottomley
2025-04-02 11:47 ` Jan Kara
2025-03-27 14:06 ` [RFC PATCH 2/4] vfs: make sb_start_write freezable James Bottomley
2025-03-27 17:36 ` Jan Kara
2025-03-27 14:06 ` [RFC PATCH 3/4] fs/super.c: introduce reverse superblock iterator and use it in emergency remount James Bottomley
2025-03-28 11:56 ` Christian Brauner
2025-03-28 12:38 ` James Bottomley
2025-03-28 16:15 ` [PATCH 0/6] Extend freeze support to suspend and hibernate Christian Brauner
2025-03-28 16:15 ` [PATCH 1/6] super: remove pointless s_root checks Christian Brauner
2025-03-28 16:15 ` [PATCH 2/6] super: simplify user_get_super() Christian Brauner
2025-03-28 16:15 ` [PATCH 3/6] super: skip dying superblocks early Christian Brauner
2025-03-28 16:15 ` [PATCH 4/6] super: use a common iterator (Part 1) Christian Brauner
2025-03-28 16:15 ` [PATCH 5/6] super: use common iterator (Part 2) Christian Brauner
2025-03-28 18:58 ` James Bottomley
2025-03-29 7:34 ` Christian Brauner
2025-03-28 16:15 ` [PATCH 6/6] super: add filesystem freezing helpers for suspend and hibernate Christian Brauner
2025-03-29 8:42 ` [PATCH v2 0/6] Extend freeze support to " Christian Brauner
2025-03-29 8:42 ` [PATCH v2 1/6] super: remove pointless s_root checks Christian Brauner
2025-03-31 9:57 ` Jan Kara
2025-06-11 16:26 ` Darrick J. Wong
2025-06-12 12:20 ` Christian Brauner
2025-03-29 8:42 ` [PATCH v2 2/6] super: simplify user_get_super() Christian Brauner
2025-03-31 9:58 ` Jan Kara
2025-03-29 8:42 ` [PATCH v2 3/6] super: skip dying superblocks early Christian Brauner
2025-03-31 10:00 ` Jan Kara
2025-03-29 8:42 ` [PATCH v2 4/6] super: use a common iterator (Part 1) Christian Brauner
2025-03-31 10:01 ` Jan Kara
2025-03-29 8:42 ` [PATCH v2 5/6] super: use common iterator (Part 2) Christian Brauner
2025-03-31 10:07 ` Jan Kara
2025-03-31 10:15 ` Christian Brauner
2025-03-29 8:42 ` [PATCH v2 6/6] super: add filesystem freezing helpers for suspend and hibernate Christian Brauner
2025-03-29 8:46 ` Christian Brauner
2025-03-31 10:23 ` Jan Kara
2025-03-31 10:25 ` Christian Brauner
2025-03-29 14:04 ` [PATCH v2 0/6] Extend freeze support to " James Bottomley
2025-03-29 17:02 ` James Bottomley
2025-03-30 8:33 ` Christian Brauner
2025-03-30 11:53 ` Christian Brauner
2025-03-30 14:00 ` James Bottomley
2025-03-31 9:13 ` Christian Brauner
2025-03-31 10:36 ` Jan Kara
2025-03-31 14:49 ` James Bottomley
2025-03-31 23:33 ` Christian Brauner
2025-03-31 12:42 ` [PATCH 0/2] efivarfs: support freeze/thaw Christian Brauner
2025-03-31 12:42 ` [PATCH 1/2] libfs: export find_next_child() Christian Brauner
2025-03-31 12:42 ` Christian Brauner [this message]
2025-03-31 14:46 ` [PATCH 2/2] efivarfs: support freeze/thaw James Bottomley
2025-03-31 15:03 ` Christian Brauner
2025-04-01 19:31 ` James Bottomley
2025-04-02 7:44 ` Christian Brauner
2025-03-31 14:05 ` [PATCH 0/2] " Ard Biesheuvel
2025-04-01 0:32 ` [PATCH 0/6] power: wire-up filesystem freeze/thaw with suspend/resume Christian Brauner
2025-04-01 0:32 ` [PATCH 1/6] ext4: replace kthread freezing with auto fs freezing Christian Brauner
2025-04-01 9:16 ` Jan Kara
2025-04-01 9:35 ` Christian Brauner
2025-04-01 10:08 ` Jan Kara
2025-04-01 0:32 ` [PATCH 2/6] btrfs: " Christian Brauner
2025-04-01 0:32 ` [PATCH 3/6] xfs: " Christian Brauner
2025-04-01 1:11 ` Dave Chinner
2025-04-01 7:17 ` Christian Brauner
2025-04-01 11:35 ` Dave Chinner
2025-04-01 12:45 ` Christian Brauner
2025-04-01 0:32 ` [PATCH 4/6] fs: add owner of freeze/thaw Christian Brauner
2025-04-01 0:32 ` [PATCH 5/6] fs: allow pagefault based writers to be frozen Christian Brauner
2025-04-01 0:32 ` [PATCH 6/6] power: freeze filesystems during suspend/resume Christian Brauner
2025-04-01 8:16 ` [PATCH 0/6] power: wire-up filesystem freeze/thaw with suspend/resume Christian Brauner
2025-04-01 9:32 ` Jan Kara
2025-04-01 13:03 ` Christian Brauner
2025-04-01 16:57 ` Jan Kara
2025-04-02 14:07 ` [PATCH v2 0/4] " Christian Brauner
2025-04-02 14:07 ` [PATCH v2 1/4] fs: add owner of freeze/thaw Christian Brauner
2025-04-03 14:56 ` Jan Kara
2025-04-03 19:33 ` Christian Brauner
2025-04-04 10:24 ` [PATCH] fs: allow nesting with FREEZE_EXCL Christian Brauner
2025-04-07 9:08 ` Christoph Hellwig
2025-05-07 11:18 ` Jan Kara
2025-05-09 10:38 ` Christian Brauner
2025-04-02 14:07 ` [PATCH v2 2/4] fs: allow all writers to be frozen Christian Brauner
2025-04-02 15:32 ` Christian Brauner
2025-04-02 16:03 ` James Bottomley
2025-04-02 16:13 ` Christian Brauner
2025-04-03 14:59 ` Jan Kara
2025-04-02 14:07 ` [PATCH v2 3/4] power: freeze filesystems during suspend/resume Christian Brauner
2025-04-03 16:29 ` Jan Kara
2025-04-02 14:07 ` [PATCH v2 4/4] kernfs: add warning about implementing freeze/thaw Christian Brauner
2025-04-03 15:00 ` Jan Kara
2025-07-20 19:23 ` [PATCH v2 0/4] power: wire-up filesystem freeze/thaw with suspend/resume Askar Safin
2025-07-21 12:09 ` Jan Kara
2025-08-04 5:31 ` Miklos Szeredi
2025-08-04 6:02 ` Askar Safin
2025-08-04 6:51 ` Sergey Senozhatsky
2025-04-01 14:14 ` [PATCH 0/6] " Peter Zijlstra
2025-04-01 14:40 ` Christian Brauner
2025-04-01 14:59 ` Peter Zijlstra
2025-04-01 17:02 ` James Bottomley
2025-04-02 7:46 ` Christian Brauner
2025-04-08 15:43 ` James Bottomley
2025-04-08 17:09 ` Luis Chamberlain
2025-04-08 17:20 ` Luis Chamberlain
2025-04-08 17:26 ` James Bottomley
2025-04-08 17:24 ` James Bottomley
2025-04-09 7:17 ` Christian Brauner
2025-03-27 14:06 ` [RFC PATCH 4/4] vfs: add filesystem freeze/thaw callbacks for power management James Bottomley
2025-03-27 18:20 ` Jan Kara
2025-03-28 14:21 ` James Bottomley
2025-03-28 14:36 ` James Bottomley
2025-03-28 10:08 ` Christian Brauner
2025-03-28 14:14 ` James Bottomley
2025-03-28 15:52 ` Christian Brauner
2025-03-28 16:15 ` James Bottomley
2025-03-29 8:23 ` Christian Brauner
2025-03-28 12:01 ` Christian Brauner
2025-03-28 14:40 ` James Bottomley
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=20250331-work-freeze-v1-2-6dfbe8253b9f@kernel.org \
--to=brauner@kernel.org \
--cc=James.Bottomley@hansenpartnership.com \
--cc=ardb@kernel.org \
--cc=boqun.feng@gmail.com \
--cc=david@fromorbit.com \
--cc=djwong@kernel.org \
--cc=hch@infradead.org \
--cc=jack@suse.cz \
--cc=linux-efi@vger.kernel.org \
--cc=linux-fsdevel@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=mcgrof@kernel.org \
--cc=mingo@redhat.com \
--cc=pavel@kernel.org \
--cc=peterz@infradead.org \
--cc=rafael@kernel.org \
--cc=will@kernel.org \
/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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).