mirror of
https://github.com/lkl/linux.git
synced 2025-12-19 16:13:19 +09:00
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 18e9e5104f ("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@kernel.org
Cc: jack@suse.cz
Cc: hch@infradead.org
Cc: ruansy.fnst@fujitsu.com
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Dave Chinner <dchinner@redhat.com>
Reviewed-by: Jan Kara <jack@suse.cz>
This commit is contained in:
@@ -1147,7 +1147,8 @@ 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? */
|
||||
struct percpu_rw_semaphore rw_sem[SB_FREEZE_LEVELS];
|
||||
};
|
||||
|
||||
@@ -1902,6 +1903,10 @@ extern loff_t vfs_dedupe_file_range_one(struct file *src_file, loff_t src_pos,
|
||||
struct file *dst_file, loff_t dst_pos,
|
||||
loff_t len, unsigned int remap_flags);
|
||||
|
||||
enum freeze_holder {
|
||||
FREEZE_HOLDER_KERNEL = (1U << 0),
|
||||
FREEZE_HOLDER_USERSPACE = (1U << 1),
|
||||
};
|
||||
|
||||
struct super_operations {
|
||||
struct inode *(*alloc_inode)(struct super_block *sb);
|
||||
@@ -1914,9 +1919,9 @@ struct super_operations {
|
||||
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_holder who);
|
||||
int (*unfreeze_fs) (struct super_block *);
|
||||
int (*statfs) (struct dentry *, struct kstatfs *);
|
||||
int (*remount_fs) (struct super_block *, int *, char *);
|
||||
@@ -2290,8 +2295,8 @@ extern int unregister_filesystem(struct file_system_type *);
|
||||
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);
|
||||
int freeze_super(struct super_block *super, enum freeze_holder who);
|
||||
int thaw_super(struct super_block *super, enum freeze_holder who);
|
||||
extern __printf(2, 3)
|
||||
int super_setup_bdi_name(struct super_block *sb, char *fmt, ...);
|
||||
extern int super_setup_bdi(struct super_block *sb);
|
||||
|
||||
Reference in New Issue
Block a user