Commit: 18e9e5104fcd breaks connection between freeze_bdev()/thaw_bdev() and freeze_super()/thaw_super() In other workds: freeze_bdev()/thaw_bdev() may be called multiple times, but freeze_super()/thaw_super() only once (will resunt -EBUSY on second call) BUT user is still allowed to mix both interfaces: freeze_bdev () call it first time ->bdev->bd_fsfreeze_count++ ->freeze_super() return 0 freeze_super() second time ->bdev->bd_fsfreeze_count++ return 0 One can call ioctl_fsthaw( #xfs_freeze -u $MNT) ioctl_fsthaw ->thaw_super() -> fs is unfrozen now return 0 This leave bdev in broken state because: bd_fsfreeze_count > 0 but superblock is not frozen. Visiable effect: 0) Any freeze_bdev() will not call freeze_super() because (bdev->bd_fsfreeze_count > 0) 1) thaw_bdev() will fail because thaw_super() will return EINVAL (filesystem is not frozen) and bdev->bd_fsfreeze_count will not being decremented. 2) filesystem may not being mounted because mount_bdev will fail because (bdev->bd_fsfreeze_count > 0) #TEST_CASE: # Use xfstests 068'th test (while true ;do dmsetup suspend $SCRATCH_DEV ;dmsetup resume $SCRATCH_DEV;done)& pid=$! ./check 068 068 068 068 068 kill $pid wait $pid In order to fix that let's always use {freeze,thaw}_bdev() functions if super block has bdev, and directly call {freeze,thaw)_super() otherwise. Signed-off-by: Dmitry Monakhov <dmonakhov@xxxxxxxxxx> --- fs/ioctl.c | 16 +++++++++++++--- 1 files changed, 13 insertions(+), 3 deletions(-) diff --git a/fs/ioctl.c b/fs/ioctl.c index 3bdad6d..ea47ccc 100644 --- a/fs/ioctl.c +++ b/fs/ioctl.c @@ -513,6 +513,7 @@ static int ioctl_fioasync(unsigned int fd, struct file *filp, static int ioctl_fsfreeze(struct file *filp) { struct super_block *sb = filp->f_path.dentry->d_inode->i_sb; + int ret = 0; if (!capable(CAP_SYS_ADMIN)) return -EPERM; @@ -521,8 +522,15 @@ static int ioctl_fsfreeze(struct file *filp) if (sb->s_op->freeze_fs == NULL) return -EOPNOTSUPP; - /* Freeze */ - return freeze_super(sb); + if (sb->s_bdev) { + struct super_block *fsb; + fsb = freeze_bdev(sb->s_bdev); + if (IS_ERR(fsb)) + ret = PTR_ERR(fsb); + } else { + ret = freeze_super(sb); + } + return ret; } static int ioctl_fsthaw(struct file *filp) @@ -532,7 +540,9 @@ static int ioctl_fsthaw(struct file *filp) if (!capable(CAP_SYS_ADMIN)) return -EPERM; - /* Thaw */ + if (sb->s_bdev) + return thaw_bdev(sb->s_bdev, sb); + return thaw_super(sb); } -- 1.7.1 -- To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html