fs: add freeze_super/thaw_super fs hooks
Currently, freezing a filesystem involves calling freeze_super, which locks sb->s_umount and then calls the fs-specific freeze_fs hook. This makes it hard for gfs2 (and potentially other cluster filesystems) to use the vfs freezing code to do freezes on all the cluster nodes. In order to communicate that a freeze has been requested, and to make sure that only one node is trying to freeze at a time, gfs2 uses a glock (sd_freeze_gl). The problem is that there is no hook for gfs2 to acquire this lock before calling freeze_super. This means that two nodes can attempt to freeze the filesystem by both calling freeze_super, acquiring the sb->s_umount lock, and then attempting to grab the cluster glock sd_freeze_gl. Only one will succeed, and the other will be stuck in freeze_super, making it impossible to finish freezing the node. To solve this problem, this patch adds the freeze_super and thaw_super hooks. If a filesystem implements these hooks, they are called instead of the vfs freeze_super and thaw_super functions. This means that every filesystem that implements these hooks must call the vfs freeze_super and thaw_super functions itself within the hook function to make use of the vfs freezing code. Reviewed-by: Jan Kara <jack@suse.cz> Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com> Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
This commit is contained in:
parent
98f1a696a1
commit
48b6bca6b7
|
@ -235,7 +235,10 @@ struct super_block *freeze_bdev(struct block_device *bdev)
|
|||
sb = get_active_super(bdev);
|
||||
if (!sb)
|
||||
goto out;
|
||||
error = freeze_super(sb);
|
||||
if (sb->s_op->freeze_super)
|
||||
error = sb->s_op->freeze_super(sb);
|
||||
else
|
||||
error = freeze_super(sb);
|
||||
if (error) {
|
||||
deactivate_super(sb);
|
||||
bdev->bd_fsfreeze_count--;
|
||||
|
@ -272,7 +275,10 @@ int thaw_bdev(struct block_device *bdev, struct super_block *sb)
|
|||
if (!sb)
|
||||
goto out;
|
||||
|
||||
error = thaw_super(sb);
|
||||
if (sb->s_op->thaw_super)
|
||||
error = sb->s_op->thaw_super(sb);
|
||||
else
|
||||
error = thaw_super(sb);
|
||||
if (error) {
|
||||
bdev->bd_fsfreeze_count++;
|
||||
mutex_unlock(&bdev->bd_fsfreeze_mutex);
|
||||
|
|
|
@ -518,10 +518,12 @@ static int ioctl_fsfreeze(struct file *filp)
|
|||
return -EPERM;
|
||||
|
||||
/* If filesystem doesn't support freeze feature, return. */
|
||||
if (sb->s_op->freeze_fs == NULL)
|
||||
if (sb->s_op->freeze_fs == NULL && sb->s_op->freeze_super == NULL)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
/* Freeze */
|
||||
if (sb->s_op->freeze_super)
|
||||
return sb->s_op->freeze_super(sb);
|
||||
return freeze_super(sb);
|
||||
}
|
||||
|
||||
|
@ -533,6 +535,8 @@ static int ioctl_fsthaw(struct file *filp)
|
|||
return -EPERM;
|
||||
|
||||
/* Thaw */
|
||||
if (sb->s_op->thaw_super)
|
||||
return sb->s_op->thaw_super(sb);
|
||||
return thaw_super(sb);
|
||||
}
|
||||
|
||||
|
|
|
@ -1577,7 +1577,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_fs) (struct super_block *);
|
||||
int (*thaw_super) (struct super_block *);
|
||||
int (*unfreeze_fs) (struct super_block *);
|
||||
int (*statfs) (struct dentry *, struct kstatfs *);
|
||||
int (*remount_fs) (struct super_block *, int *, char *);
|
||||
|
|
Loading…
Reference in New Issue