Skip to content

Commit 8dd5353

Browse files
committed
Merge tag 'vfs-6.16-rc1.super' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
Pull vfs freezing updates from Christian Brauner: "This contains various filesystem freezing related work for this cycle: - Allow the power subsystem to support filesystem freeze for suspend and hibernate. Now all the pieces are in place to actually allow the power subsystem to freeze/thaw filesystems during suspend/resume. Filesystems are only frozen and thawed if the power subsystem does actually own the freeze. If the filesystem is already frozen by the time we've frozen all userspace processes we don't care to freeze it again. That's userspace's job once the process resumes. We only actually freeze filesystems if we absolutely have to and we ignore other failures to freeze. We could bubble up errors and fail suspend/resume if the error isn't EBUSY (aka it's already frozen) but I don't think that this is worth it. Filesystem freezing during suspend/resume is best-effort. If the user has 500 ext4 filesystems mounted and 4 fail to freeze for whatever reason then we simply skip them. What we have now is already a big improvement and let's see how we fare with it before making our lives even harder (and uglier) than we have to. - Allow efivars to support freeze and thaw 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. 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. If userspace initiated a freeze/thaw cycle they would need CAP_SYS_ADMIN in the initial user namespace (as that's where efivarfs is mounted) so it can't be triggered by random userspace. IOW, we really really don't care" * tag 'vfs-6.16-rc1.super' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs: f2fs: fix freezing filesystem during resize kernfs: add warning about implementing freeze/thaw efivarfs: support freeze/thaw power: freeze filesystems during suspend/resume libfs: export find_next_child() super: add filesystem freezing helpers for suspend and hibernate gfs2: pass through holder from the VFS for freeze/thaw super: use common iterator (Part 2) super: use a common iterator (Part 1) super: skip dying superblocks early super: simplify user_get_super() super: remove pointless s_root checks fs: allow all writers to be frozen locking/percpu-rwsem: add freezable alternative to down_read
2 parents 181d8e3 + 1afe9e7 commit 8dd5353

File tree

19 files changed

+417
-276
lines changed

19 files changed

+417
-276
lines changed

fs/efivarfs/internal.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ struct efivarfs_fs_info {
1717
struct efivarfs_mount_opts mount_opts;
1818
struct super_block *sb;
1919
struct notifier_block nb;
20-
struct notifier_block pm_nb;
2120
};
2221

2322
struct efi_variable {

fs/efivarfs/super.c

Lines changed: 51 additions & 144 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include <linux/namei.h>
2222

2323
#include "internal.h"
24+
#include "../internal.h"
2425

2526
static int efivarfs_ops_notifier(struct notifier_block *nb, unsigned long event,
2627
void *data)
@@ -120,12 +121,18 @@ static int efivarfs_statfs(struct dentry *dentry, struct kstatfs *buf)
120121

121122
return 0;
122123
}
124+
125+
static int efivarfs_freeze_fs(struct super_block *sb);
126+
static int efivarfs_unfreeze_fs(struct super_block *sb);
127+
123128
static const struct super_operations efivarfs_ops = {
124129
.statfs = efivarfs_statfs,
125130
.drop_inode = generic_delete_inode,
126131
.alloc_inode = efivarfs_alloc_inode,
127132
.free_inode = efivarfs_free_inode,
128133
.show_options = efivarfs_show_options,
134+
.freeze_fs = efivarfs_freeze_fs,
135+
.unfreeze_fs = efivarfs_unfreeze_fs,
129136
};
130137

131138
/*
@@ -365,8 +372,6 @@ static int efivarfs_fill_super(struct super_block *sb, struct fs_context *fc)
365372
if (err)
366373
return err;
367374

368-
register_pm_notifier(&sfi->pm_nb);
369-
370375
return efivar_init(efivarfs_callback, sb, true);
371376
}
372377

@@ -391,48 +396,6 @@ static const struct fs_context_operations efivarfs_context_ops = {
391396
.reconfigure = efivarfs_reconfigure,
392397
};
393398

394-
struct efivarfs_ctx {
395-
struct dir_context ctx;
396-
struct super_block *sb;
397-
struct dentry *dentry;
398-
};
399-
400-
static bool efivarfs_actor(struct dir_context *ctx, const char *name, int len,
401-
loff_t offset, u64 ino, unsigned mode)
402-
{
403-
unsigned long size;
404-
struct efivarfs_ctx *ectx = container_of(ctx, struct efivarfs_ctx, ctx);
405-
struct dentry *dentry = try_lookup_noperm(&QSTR_LEN(name, len),
406-
ectx->sb->s_root);
407-
struct inode *inode;
408-
struct efivar_entry *entry;
409-
int err;
410-
411-
if (IS_ERR_OR_NULL(dentry))
412-
return true;
413-
414-
inode = d_inode(dentry);
415-
entry = efivar_entry(inode);
416-
417-
err = efivar_entry_size(entry, &size);
418-
size += sizeof(__u32); /* attributes */
419-
if (err)
420-
size = 0;
421-
422-
inode_lock_nested(inode, I_MUTEX_CHILD);
423-
i_size_write(inode, size);
424-
inode_unlock(inode);
425-
426-
if (!size) {
427-
ectx->dentry = dentry;
428-
return false;
429-
}
430-
431-
dput(dentry);
432-
433-
return true;
434-
}
435-
436399
static int efivarfs_check_missing(efi_char16_t *name16, efi_guid_t vendor,
437400
unsigned long name_size, void *data)
438401
{
@@ -469,111 +432,59 @@ static int efivarfs_check_missing(efi_char16_t *name16, efi_guid_t vendor,
469432
return err;
470433
}
471434

472-
static void efivarfs_deactivate_super_work(struct work_struct *work)
473-
{
474-
struct super_block *s = container_of(work, struct super_block,
475-
destroy_work);
476-
/*
477-
* note: here s->destroy_work is free for reuse (which
478-
* will happen in deactivate_super)
479-
*/
480-
deactivate_super(s);
481-
}
482-
483435
static struct file_system_type efivarfs_type;
484436

485-
static int efivarfs_pm_notify(struct notifier_block *nb, unsigned long action,
486-
void *ptr)
437+
static int efivarfs_freeze_fs(struct super_block *sb)
487438
{
488-
struct efivarfs_fs_info *sfi = container_of(nb, struct efivarfs_fs_info,
489-
pm_nb);
490-
struct path path;
491-
struct efivarfs_ctx ectx = {
492-
.ctx = {
493-
.actor = efivarfs_actor,
494-
},
495-
.sb = sfi->sb,
496-
};
497-
struct file *file;
498-
struct super_block *s = sfi->sb;
499-
static bool rescan_done = true;
500-
501-
if (action == PM_HIBERNATION_PREPARE) {
502-
rescan_done = false;
503-
return NOTIFY_OK;
504-
} else if (action != PM_POST_HIBERNATION) {
505-
return NOTIFY_DONE;
506-
}
507-
508-
if (rescan_done)
509-
return NOTIFY_DONE;
510-
511-
/* ensure single superblock is alive and pin it */
512-
if (!atomic_inc_not_zero(&s->s_active))
513-
return NOTIFY_DONE;
514-
515-
pr_info("efivarfs: resyncing variable state\n");
516-
517-
path.dentry = sfi->sb->s_root;
518-
519-
/*
520-
* do not add SB_KERNMOUNT which a single superblock could
521-
* expose to userspace and which also causes MNT_INTERNAL, see
522-
* below
523-
*/
524-
path.mnt = vfs_kern_mount(&efivarfs_type, 0,
525-
efivarfs_type.name, NULL);
526-
if (IS_ERR(path.mnt)) {
527-
pr_err("efivarfs: internal mount failed\n");
528-
/*
529-
* We may be the last pinner of the superblock but
530-
* calling efivarfs_kill_sb from within the notifier
531-
* here would deadlock trying to unregister it
532-
*/
533-
INIT_WORK(&s->destroy_work, efivarfs_deactivate_super_work);
534-
schedule_work(&s->destroy_work);
535-
return PTR_ERR(path.mnt);
536-
}
537-
538-
/* path.mnt now has pin on superblock, so this must be above one */
539-
atomic_dec(&s->s_active);
540-
541-
file = kernel_file_open(&path, O_RDONLY | O_DIRECTORY | O_NOATIME,
542-
current_cred());
543-
/*
544-
* safe even if last put because no MNT_INTERNAL means this
545-
* will do delayed deactivate_super and not deadlock
546-
*/
547-
mntput(path.mnt);
548-
if (IS_ERR(file))
549-
return NOTIFY_DONE;
439+
/* Nothing for us to do. */
440+
return 0;
441+
}
550442

551-
rescan_done = true;
443+
static int efivarfs_unfreeze_fs(struct super_block *sb)
444+
{
445+
struct dentry *child = NULL;
552446

553447
/*
554-
* First loop over the directory and verify each entry exists,
555-
* removing it if it doesn't
448+
* Unconditionally resync the variable state on a thaw request.
449+
* Given the size of efivarfs it really doesn't matter to simply
450+
* iterate through all of the entries and resync. Freeze/thaw
451+
* requests are rare enough for that to not matter and the
452+
* number of entries is pretty low too. So we really don't care.
556453
*/
557-
file->f_pos = 2; /* skip . and .. */
558-
do {
559-
ectx.dentry = NULL;
560-
iterate_dir(file, &ectx.ctx);
561-
if (ectx.dentry) {
562-
pr_info("efivarfs: removing variable %pd\n",
563-
ectx.dentry);
564-
simple_recursive_removal(ectx.dentry, NULL);
565-
dput(ectx.dentry);
454+
pr_info("efivarfs: resyncing variable state\n");
455+
for (;;) {
456+
int err;
457+
unsigned long size = 0;
458+
struct inode *inode;
459+
struct efivar_entry *entry;
460+
461+
child = find_next_child(sb->s_root, child);
462+
if (!child)
463+
break;
464+
465+
inode = d_inode(child);
466+
entry = efivar_entry(inode);
467+
468+
err = efivar_entry_size(entry, &size);
469+
if (err)
470+
size = 0;
471+
else
472+
size += sizeof(__u32);
473+
474+
inode_lock(inode);
475+
i_size_write(inode, size);
476+
inode_unlock(inode);
477+
478+
/* The variable doesn't exist anymore, delete it. */
479+
if (!size) {
480+
pr_info("efivarfs: removing variable %pd\n", child);
481+
simple_recursive_removal(child, NULL);
566482
}
567-
} while (ectx.dentry);
568-
fput(file);
569-
570-
/*
571-
* then loop over variables, creating them if there's no matching
572-
* dentry
573-
*/
574-
efivar_init(efivarfs_check_missing, sfi->sb, false);
483+
}
575484

576-
return NOTIFY_OK;
485+
efivar_init(efivarfs_check_missing, sb, false);
486+
pr_info("efivarfs: finished resyncing variable state\n");
487+
return 0;
577488
}
578489

579490
static int efivarfs_init_fs_context(struct fs_context *fc)
@@ -593,9 +504,6 @@ static int efivarfs_init_fs_context(struct fs_context *fc)
593504
fc->s_fs_info = sfi;
594505
fc->ops = &efivarfs_context_ops;
595506

596-
sfi->pm_nb.notifier_call = efivarfs_pm_notify;
597-
sfi->pm_nb.priority = 0;
598-
599507
return 0;
600508
}
601509

@@ -605,7 +513,6 @@ static void efivarfs_kill_sb(struct super_block *sb)
605513

606514
blocking_notifier_chain_unregister(&efivar_ops_nh, &sfi->nb);
607515
kill_litter_super(sb);
608-
unregister_pm_notifier(&sfi->pm_nb);
609516

610517
kfree(sfi);
611518
}

fs/f2fs/gc.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2271,12 +2271,12 @@ int f2fs_resize_fs(struct file *filp, __u64 block_count)
22712271
if (err)
22722272
return err;
22732273

2274-
err = freeze_super(sbi->sb, FREEZE_HOLDER_USERSPACE);
2274+
err = freeze_super(sbi->sb, FREEZE_HOLDER_KERNEL, NULL);
22752275
if (err)
22762276
return err;
22772277

22782278
if (f2fs_readonly(sbi->sb)) {
2279-
err = thaw_super(sbi->sb, FREEZE_HOLDER_USERSPACE);
2279+
err = thaw_super(sbi->sb, FREEZE_HOLDER_KERNEL, NULL);
22802280
if (err)
22812281
return err;
22822282
return -EROFS;
@@ -2333,6 +2333,6 @@ int f2fs_resize_fs(struct file *filp, __u64 block_count)
23332333
out_err:
23342334
f2fs_up_write(&sbi->cp_global_sem);
23352335
f2fs_up_write(&sbi->gc_lock);
2336-
thaw_super(sbi->sb, FREEZE_HOLDER_USERSPACE);
2336+
thaw_super(sbi->sb, FREEZE_HOLDER_KERNEL, NULL);
23372337
return err;
23382338
}

fs/gfs2/super.c

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -674,15 +674,15 @@ static int gfs2_sync_fs(struct super_block *sb, int wait)
674674
return sdp->sd_log_error;
675675
}
676676

677-
static int gfs2_do_thaw(struct gfs2_sbd *sdp)
677+
static int gfs2_do_thaw(struct gfs2_sbd *sdp, enum freeze_holder who, const void *freeze_owner)
678678
{
679679
struct super_block *sb = sdp->sd_vfs;
680680
int error;
681681

682682
error = gfs2_freeze_lock_shared(sdp);
683683
if (error)
684684
goto fail;
685-
error = thaw_super(sb, FREEZE_HOLDER_USERSPACE);
685+
error = thaw_super(sb, who, freeze_owner);
686686
if (!error)
687687
return 0;
688688

@@ -703,14 +703,14 @@ void gfs2_freeze_func(struct work_struct *work)
703703
if (test_bit(SDF_FROZEN, &sdp->sd_flags))
704704
goto freeze_failed;
705705

706-
error = freeze_super(sb, FREEZE_HOLDER_USERSPACE);
706+
error = freeze_super(sb, FREEZE_HOLDER_USERSPACE, NULL);
707707
if (error)
708708
goto freeze_failed;
709709

710710
gfs2_freeze_unlock(sdp);
711711
set_bit(SDF_FROZEN, &sdp->sd_flags);
712712

713-
error = gfs2_do_thaw(sdp);
713+
error = gfs2_do_thaw(sdp, FREEZE_HOLDER_USERSPACE, NULL);
714714
if (error)
715715
goto out;
716716

@@ -728,10 +728,13 @@ void gfs2_freeze_func(struct work_struct *work)
728728
/**
729729
* gfs2_freeze_super - prevent further writes to the filesystem
730730
* @sb: the VFS structure for the filesystem
731+
* @who: freeze flags
732+
* @freeze_owner: owner of the freeze
731733
*
732734
*/
733735

734-
static int gfs2_freeze_super(struct super_block *sb, enum freeze_holder who)
736+
static int gfs2_freeze_super(struct super_block *sb, enum freeze_holder who,
737+
const void *freeze_owner)
735738
{
736739
struct gfs2_sbd *sdp = sb->s_fs_info;
737740
int error;
@@ -744,7 +747,7 @@ static int gfs2_freeze_super(struct super_block *sb, enum freeze_holder who)
744747
}
745748

746749
for (;;) {
747-
error = freeze_super(sb, FREEZE_HOLDER_USERSPACE);
750+
error = freeze_super(sb, who, freeze_owner);
748751
if (error) {
749752
fs_info(sdp, "GFS2: couldn't freeze filesystem: %d\n",
750753
error);
@@ -758,7 +761,7 @@ static int gfs2_freeze_super(struct super_block *sb, enum freeze_holder who)
758761
break;
759762
}
760763

761-
error = gfs2_do_thaw(sdp);
764+
error = gfs2_do_thaw(sdp, who, freeze_owner);
762765
if (error)
763766
goto out;
764767

@@ -796,10 +799,13 @@ static int gfs2_freeze_fs(struct super_block *sb)
796799
/**
797800
* gfs2_thaw_super - reallow writes to the filesystem
798801
* @sb: the VFS structure for the filesystem
802+
* @who: freeze flags
803+
* @freeze_owner: owner of the freeze
799804
*
800805
*/
801806

802-
static int gfs2_thaw_super(struct super_block *sb, enum freeze_holder who)
807+
static int gfs2_thaw_super(struct super_block *sb, enum freeze_holder who,
808+
const void *freeze_owner)
803809
{
804810
struct gfs2_sbd *sdp = sb->s_fs_info;
805811
int error;
@@ -814,7 +820,7 @@ static int gfs2_thaw_super(struct super_block *sb, enum freeze_holder who)
814820
atomic_inc(&sb->s_active);
815821
gfs2_freeze_unlock(sdp);
816822

817-
error = gfs2_do_thaw(sdp);
823+
error = gfs2_do_thaw(sdp, who, freeze_owner);
818824

819825
if (!error) {
820826
clear_bit(SDF_FREEZE_INITIATOR, &sdp->sd_flags);

fs/gfs2/sys.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -174,10 +174,10 @@ static ssize_t freeze_store(struct gfs2_sbd *sdp, const char *buf, size_t len)
174174

175175
switch (n) {
176176
case 0:
177-
error = thaw_super(sdp->sd_vfs, FREEZE_HOLDER_USERSPACE);
177+
error = thaw_super(sdp->sd_vfs, FREEZE_HOLDER_USERSPACE, NULL);
178178
break;
179179
case 1:
180-
error = freeze_super(sdp->sd_vfs, FREEZE_HOLDER_USERSPACE);
180+
error = freeze_super(sdp->sd_vfs, FREEZE_HOLDER_USERSPACE, NULL);
181181
break;
182182
default:
183183
return -EINVAL;

0 commit comments

Comments
 (0)