On Sun, Jun 11, 2023 at 08:58:40PM -0700, Christoph Hellwig wrote: > On Sun, Jun 11, 2023 at 08:15:22PM -0700, Darrick J. Wong wrote: > > From: Darrick J. Wong <djwong@xxxxxxxxxx> > > > > 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. > > > > I wonder if the f2fs/gfs2 code should be using a kernel freeze here, but > > for now we'll use FREEZE_HOLDER_USERSPACE to preserve existing > > behaviors. > > > > Cc: mcgrof@xxxxxxxxxx > > Cc: jack@xxxxxxx > > Cc: hch@xxxxxxxxxxxxx > > Cc: ruansy.fnst@xxxxxxxxxxx > > Signed-off-by: Darrick J. Wong <djwong@xxxxxxxxxx> > > --- > > Documentation/filesystems/vfs.rst | 4 +- > > block/bdev.c | 8 ++-- > > fs/f2fs/gc.c | 4 +- > > fs/gfs2/glops.c | 2 - > > fs/gfs2/super.c | 6 +-- > > fs/gfs2/sys.c | 4 +- > > fs/gfs2/util.c | 2 - > > fs/ioctl.c | 8 ++-- > > fs/super.c | 79 +++++++++++++++++++++++++++++++++---- > > include/linux/fs.h | 15 +++++-- > > 10 files changed, 100 insertions(+), 32 deletions(-) > > > > > > diff --git a/Documentation/filesystems/vfs.rst b/Documentation/filesystems/vfs.rst > > index 769be5230210..41cf2a56cbca 100644 > > --- a/Documentation/filesystems/vfs.rst > > +++ b/Documentation/filesystems/vfs.rst > > @@ -260,9 +260,9 @@ filesystem. The following members are defined: > > void (*evict_inode) (struct inode *); > > void (*put_super) (struct super_block *); > > int (*sync_fs)(struct super_block *sb, int wait); > > - int (*freeze_super) (struct super_block *); > > + int (*freeze_super) (struct super_block *, enum freeze_holder who); > > int (*freeze_fs) (struct super_block *); > > - int (*thaw_super) (struct super_block *); > > + int (*thaw_super) (struct super_block *, enum freeze_wholder who); > > Nit: Can you spell out the sb paramter as well and avoid the overly long > lines here? Done. > > +static int freeze_frozen_super(struct super_block *sb, enum freeze_holder who) > > +{ > > + /* Someone else already holds this type of freeze */ > > + if (sb->s_writers.freeze_holders & who) > > + return -EBUSY; > > + > > + WARN_ON(sb->s_writers.freeze_holders == 0); > > + > > + sb->s_writers.freeze_holders |= who; > > + return 0; > > +} > > So with the simplification I'm not even sure we need this helper > anymore. But I could live with it either way. Ok, gone. It makes the code flow rather easier to understand, especially given Jan's reply asking for a shared freeze to leave s_active elevated by 2. > > /** > > * 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 > > I think the cnonstants should use a % prefix for kerneldoc to notice > them. Also I suspect something like: > > * @who: context that wants to free > > and then in the body: > > * @who should be: > * * %FREEZE_HOLDER_USERSPACE if userspace wants to freeze the fs > * * %FREEZE_HOLDER_KERNEL if the kernel wants to freeze it > > for better rendering of the comments. Same applies for the thaw side. Done. Thanks for the kerneldoc, I can never keep rst and kerneldoc straight anymore. > > +static int thaw_super_locked(struct super_block *sb, enum freeze_holder who) > > { > > int error; > > > > + if (sb->s_writers.frozen == SB_FREEZE_COMPLETE) { > > + error = try_thaw_shared_super(sb, who); > > + if (error != 1) { > > + up_write(&sb->s_umount); > > + return error; > > + } > > + } > > + > > if (sb->s_writers.frozen != SB_FREEZE_COMPLETE) { > > Make this and > > } else { > > instead of checking the same condition twice? Ok. > > +extern int freeze_super(struct super_block *super, enum freeze_holder who); > > +extern int thaw_super(struct super_block *super, enum freeze_holder who); > > .. and drop the pointless externs here. Ok done. > Except for these various nitpicks this looks good: > > Reviewed-by: Christoph Hellwig <hch@xxxxxx> Thanks! --D