fsfreeze: check ioctls
Subsystems (4)
cover fsfreeze: check ioctls
The current fsfreeze API lacks a method to check the current freeze status of a superblock. One might be tempted to think that a new vfs ioctl is all we need, but with the current implemetation of fsfreeze it it is possible to umount a freezed filesystem, which means that the only way to check the freeze status is through the block device. For a moment I thought I could get without the vfs version but then I realized that the block device ioctl would not play well with btrfs.
Because of all of the above I ended up implementing both. Al also suggested [1] a thaw-by-block-device ioctl which I am currently working on.
PATCH 1/2 fsfreeze: add FIISFROZEN ioctl
The FIISFROZEN ioctl can be use by HA and monitoring software to check the freeze state of a mounted filesystem.
---
fs/compat_ioctl.c +1 -0
@@ -883,6 +883,7 @@ COMPATIBLE_IOCTL(FIGETBSZ)/* 'X' - originally XFS but some now in the VFS */ COMPATIBLE_IOCTL(FIFREEZE) COMPATIBLE_IOCTL(FITHAW) +COMPATIBLE_IOCTL(FIISFROZEN) COMPATIBLE_IOCTL(KDGETKEYCODE) COMPATIBLE_IOCTL(KDSETKEYCODE) COMPATIBLE_IOCTL(KDGKBTYPE)
fs/ioctl.c +16 -0
@@ -536,6 +536,16 @@ static int ioctl_fsthaw(struct file *filreturn thaw_super (sb); } +static int ioctl_fs_isfrozen (struct file *filp) +{ +struct super_block *sb = filp->f_path.dentry->d_inode->i_sb; + +if (!capable (CAP_SYS_ADMIN )) +return -EPERM ; + +return isfrozen_super (sb); +} +/* * When you add any new common ioctls to the switches above and below * please update compat_sys_ioctl() too.
@@ -585,6 +595,12 @@ int do_vfs_ioctl(struct file *filp, unsi error =ioctl_fsthaw (filp);break ; +case FIISFROZEN : + error =ioctl_fs_isfrozen (filp); +if (error >=0 ) +return put_user (error, (int __user *)arg); +break ; +case FS_IOC_FIEMAP :return ioctl_fiemap (filp, arg);
fs/super.c +5 -0
@@ -1057,3 +1057,8 @@ out:return 0 ; }EXPORT_SYMBOL (thaw_super); + +int isfrozen_super (struct super_block *sb) +{ +return sb->s_frozen >SB_UNFROZEN ?1 :0 ; +}
include/linux/fs.h +2 -0
@@ -324,6 +325,7 @@ struct inodes_stat_t {#define FIFREEZE _IOWR('X', 119, int)/* Freeze */ #define FITHAW _IOWR('X', 120, int)/* Thaw */ #define FITRIM _IOWR('X', 121, struct fstrim_range)/* Trim */ +#define FIISFROZEN _IOR('X', 122, int)/* get sb freeze state */ #define FS_IOC_GETFLAGS _IOR('f', 1, long)#define FS_IOC_SETFLAGS _IOW('f', 2, long)
@@ -1882,6 +1884,7 @@ extern int fd_statfs(int, struct kstatfsextern int statfs_by_dentry (struct dentry *,struct kstatfs *);extern int freeze_super (struct super_block *super);extern int thaw_super (struct super_block *super); +extern int isfrozen_super (struct super_block *sb);extern int current_umask (void );
PATCH 2/2 fsfreeze: add BLKISFROZEN ioctl
In reply to Fernando Luis Vazquez CaoThe FIISFROZEN ioctl can be use by HA and monitoring software to check the freeze state of the filesystem sitting on top of a block device. This will not work for filesystems that can handle multiple devices, i.e. btrfs.
---
block/compat_ioctl.c +7 -0
@@ -757,6 +757,13 @@ long compat_blkdev_ioctl(struct file *ficase BLKTRACETEARDOWN :/* compatible */ ret =blk_trace_ioctl (bdev, cmd,compat_ptr (arg));return ret; +case BLKISFROZEN : +if (!capable (CAP_SYS_ADMIN )) +return -EPERM ; + ret =isfrozen_bdev (bdev); +if (ret >=0 ) +return compat_put_int (arg, ret); +return ret;default :if (disk->fops->compat_ioctl) ret = disk->fops->compat_ioctl (bdev, mode, cmd, arg);
block/ioctl.c +7 -0
@@ -322,6 +322,13 @@ int blkdev_ioctl(struct block_device *bdcase BLKTRACETEARDOWN : ret =blk_trace_ioctl (bdev, cmd, (char __user *) arg);break ; +case BLKISFROZEN : +if (!capable (CAP_SYS_ADMIN )) +return -EPERM ; + ret =isfrozen_bdev (bdev); +if (ret >=0 ) +return put_int (arg, ret); +return ret;default : ret =__blkdev_driver_ioctl (bdev, mode, cmd, arg); }
fs/block_dev.c +19 -0
@@ -310,6 +310,25 @@ out: }EXPORT_SYMBOL (thaw_bdev); +int isfrozen_bdev (struct block_device *bdev) +{ +int ret; +struct super_block *sb; + +mutex_lock (&bdev->bd_fsfreeze_mutex); + + ret = -EINVAL ; + sb =get_active_super (bdev); +if (!sb) + goto out; + ret =isfrozen_super (sb); +deactivate_super (sb); +out: +mutex_unlock (&bdev->bd_fsfreeze_mutex); + +return ret; +} +static int blkdev_writepage (struct page *page,struct writeback_control *wbc) {return block_write_full_page (page, blkdev_get_block, wbc);
include/linux/fs.h +7 -0
@@ -317,6 +317,7 @@ struct inodes_stat_t {#define BLKPBSZGET _IO(0x12,123)#define BLKDISCARDZEROES _IO(0x12,124)#define BLKSECDISCARD _IO(0x12,125) +#define BLKISFROZEN _IOR(0x12,126, int)/* get file system freeze state */ #define BMAP_IOCTL 1/* obsolete - kept for compatibility */ #define FIBMAP _IO(0x00,1)/* bmap access */
@@ -2036,6 +2039,7 @@ extern int sync_blockdev(struct block_deextern struct super_block *freeze_bdev (struct block_device *);extern void emergency_thaw_all (void );extern int thaw_bdev (struct block_device *bdev,struct super_block *sb); +extern int isfrozen_bdev (struct block_device *bdev);extern int fsync_bdev (struct block_device *);#else static inline void bd_forget (struct inode *inode) {}
@@ -2051,6 +2055,11 @@ static inline int thaw_bdev(struct block {return 0 ; } + +static int isfrozen_bdev (struct block_device *bdev) +{ +return 0 ; +}#endif extern int sync_filesystem (struct super_block *);extern const struct file_operations def_blk_fops;
cover fsfreeze: new API
In reply to Fernando Luis Vazquez CaoThere are a few with issues with how freeze works in current kernels:
- Unmounting: It is possible to umount a frozen filesystem; the freeze code holds an active reference to the superblock so it does not go away. Since it is not possible to thaw by block device, thawing an unmounted filesystem involves mounting it again and using the current vfs freeze API.
- There is no check API: There is no easy way to know whether a filesystem is frozen or not.
- Foolproofness: Quite often the freeze/thaw process is handled from a daemon. In such cases we have to make really sure that the process does not go away or is killed while the filesystem is frozen; there is no check API so it is not always easy to figure out what is going on. With the advent of virtualization things got even funnier; in some cases not even the root user is aware of the existence of such daemon (usually a guest agent that freezes the guests filesystems before taking a storage snapshot).
I cooked some patches that add the long missing check ioctls and a new freeze API, which should (modulo bugs) the current situation:
- Check ioctls
[1/4] fsfreeze: add vfs ioctl to check freeze state
Adds a vfs ioctl to check the freeze state.
[2/4] fsfreeze: add block device ioctl to check freeze state
Adds a block device ioctl to check the freeze state. This is needed because it possible to umount frozen filesystems.
- New freeze API
[3/4] fsfreeze: add ioctl to create a fd for freeze control
Adds a new ioctl that freezes the indicated filesystem and returns a file descriptor; as long as that file descriptor is held open, the filesystem remains open.
[4/4] fsfreeze: add freeze fd ioctls
Adds new ioctls that operate on the file descriptor described in the previous patch; these can be used to freeze/thaw the filesystem and check the freeze state of the filesystem, thus avoiding the need to get new file descriptors constantly.
PATCH 1/4 fsfreeze: add vfs ioctl to check freeze state
The FIISFROZEN ioctl can be use by HA and monitoring software to check the freeze state of a mounted filesystem.
---
fs/compat_ioctl.c +1 -0
@@ -883,6 +883,7 @@ COMPATIBLE_IOCTL(FIGETBSZ)/* 'X' - originally XFS but some now in the VFS */ COMPATIBLE_IOCTL(FIFREEZE) COMPATIBLE_IOCTL(FITHAW) +COMPATIBLE_IOCTL(FIISFROZEN) COMPATIBLE_IOCTL(KDGETKEYCODE) COMPATIBLE_IOCTL(KDSETKEYCODE) COMPATIBLE_IOCTL(KDGKBTYPE)
fs/ioctl.c +16 -0
@@ -536,6 +536,16 @@ static int ioctl_fsthaw(struct file *filreturn thaw_super (sb); } +static int ioctl_fs_isfrozen (struct file *filp) +{ +struct super_block *sb = filp->f_path.dentry->d_inode->i_sb; + +if (!capable (CAP_SYS_ADMIN )) +return -EPERM ; + +return isfrozen_super (sb); +} +/* * When you add any new common ioctls to the switches above and below * please update compat_sys_ioctl() too.
@@ -585,6 +595,12 @@ int do_vfs_ioctl(struct file *filp, unsi error =ioctl_fsthaw (filp);break ; +case FIISFROZEN : + error =ioctl_fs_isfrozen (filp); +if (error >=0 ) +return put_user (error, (int __user *)arg); +break ; +case FS_IOC_FIEMAP :return ioctl_fiemap (filp, arg);
fs/super.c +5 -0
@@ -1057,3 +1057,8 @@ out:return 0 ; }EXPORT_SYMBOL (thaw_super); + +int isfrozen_super (struct super_block *sb) +{ +return sb->s_frozen >SB_UNFROZEN ?1 :0 ; +}
include/linux/fs.h +2 -0
@@ -324,6 +325,7 @@ struct inodes_stat_t {#define FIFREEZE _IOWR('X', 119, int)/* Freeze */ #define FITHAW _IOWR('X', 120, int)/* Thaw */ #define FITRIM _IOWR('X', 121, struct fstrim_range)/* Trim */ +#define FIISFROZEN _IOR('X', 122, int)/* get sb freeze state */ #define FS_IOC_GETFLAGS _IOR('f', 1, long)#define FS_IOC_SETFLAGS _IOW('f', 2, long)
@@ -1882,6 +1884,7 @@ extern int fd_statfs(int, struct kstatfsextern int statfs_by_dentry (struct dentry *,struct kstatfs *);extern int freeze_super (struct super_block *super);extern int thaw_super (struct super_block *super); +extern int isfrozen_super (struct super_block *sb);extern int current_umask (void );
PATCH 2/4 fsfreeze: add block device ioctl to check freeze state
In reply to Fernando Luis Vazquez CaoThe BLKISFROZEN ioctl can be use by HA and monitoring software to check the freeze state of the filesystem sitting on top of a block device. This will not work for filesystems that can handle multiple devices, i.e. btrfs.
---
block/compat_ioctl.c +7 -0
@@ -757,6 +757,13 @@ long compat_blkdev_ioctl(struct file *ficase BLKTRACETEARDOWN :/* compatible */ ret =blk_trace_ioctl (bdev, cmd,compat_ptr (arg));return ret; +case BLKISFROZEN : +if (!capable (CAP_SYS_ADMIN )) +return -EPERM ; + ret =isfrozen_bdev (bdev); +if (ret >=0 ) +return compat_put_int (arg, ret); +return ret;default :if (disk->fops->compat_ioctl) ret = disk->fops->compat_ioctl (bdev, mode, cmd, arg);
block/ioctl.c +7 -0
@@ -322,6 +322,13 @@ int blkdev_ioctl(struct block_device *bdcase BLKTRACETEARDOWN : ret =blk_trace_ioctl (bdev, cmd, (char __user *) arg);break ; +case BLKISFROZEN : +if (!capable (CAP_SYS_ADMIN )) +return -EPERM ; + ret =isfrozen_bdev (bdev); +if (ret >=0 ) +return put_int (arg, ret); +return ret;default : ret =__blkdev_driver_ioctl (bdev, mode, cmd, arg); }
fs/block_dev.c +19 -0
@@ -310,6 +310,25 @@ out: }EXPORT_SYMBOL (thaw_bdev); +int isfrozen_bdev (struct block_device *bdev) +{ +int ret; +struct super_block *sb; + +mutex_lock (&bdev->bd_fsfreeze_mutex); + + ret = -EINVAL ; + sb =get_active_super (bdev); +if (!sb) + goto out; + ret =isfrozen_super (sb); +deactivate_super (sb); +out: +mutex_unlock (&bdev->bd_fsfreeze_mutex); + +return ret; +} +static int blkdev_writepage (struct page *page,struct writeback_control *wbc) {return block_write_full_page (page, blkdev_get_block, wbc);
include/linux/fs.h +7 -0
@@ -317,6 +317,7 @@ struct inodes_stat_t {#define BLKPBSZGET _IO(0x12,123)#define BLKDISCARDZEROES _IO(0x12,124)#define BLKSECDISCARD _IO(0x12,125) +#define BLKISFROZEN _IOR(0x12,126, int)/* get file system freeze state */ #define BMAP_IOCTL 1/* obsolete - kept for compatibility */ #define FIBMAP _IO(0x00,1)/* bmap access */
@@ -2036,6 +2039,7 @@ extern int sync_blockdev(struct block_deextern struct super_block *freeze_bdev (struct block_device *);extern void emergency_thaw_all (void );extern int thaw_bdev (struct block_device *bdev,struct super_block *sb); +extern int isfrozen_bdev (struct block_device *bdev);extern int fsync_bdev (struct block_device *);#else static inline void bd_forget (struct inode *inode) {}
@@ -2051,6 +2055,11 @@ static inline int thaw_bdev(struct block {return 0 ; } + +static int isfrozen_bdev (struct block_device *bdev) +{ +return 0 ; +}#endif extern int sync_filesystem (struct super_block *);extern const struct file_operations def_blk_fops;
PATCH 3/4 fsfreeze: add ioctl to create a fd for freeze control
In reply to Fernando Luis Vazquez CaoAdds a new ioctl, FIGETFREEZEFD, which freezes the indicated filesystem and returns a file descriptor; as long as that file descriptor is held open, the filesystem remains open.
---
fs/compat_ioctl.c +1 -0
@@ -882,6 +882,7 @@ COMPATIBLE_IOCTL(FIBMAP) COMPATIBLE_IOCTL(FIGETBSZ) /* 'X' - originally XFS but some now in the VFS */ COMPATIBLE_IOCTL(FIFREEZE) +COMPATIBLE_IOCTL(FIGETFREEZEFD) COMPATIBLE_IOCTL(FITHAW) COMPATIBLE_IOCTL(FIISFROZEN) COMPATIBLE_IOCTL(KDGETKEYCODE)
fs/ioctl.c +79 -0
97 lines not on this page · raw message
include/linux/fs.h +1 -0
@@ -326,6 +326,7 @@ struct inodes_stat_t {#define FITHAW _IOWR('X', 120, int)/* Thaw */ #define FITRIM _IOWR('X', 121, struct fstrim_range)/* Trim */ #define FIISFROZEN _IOR('X', 122, int)/* get sb freeze state */ +#define FIGETFREEZEFD _IOWR('X', 123, int)#define FS_IOC_GETFLAGS _IOR('f', 1, long)#define FS_IOC_SETFLAGS _IOW('f', 2, long)
PATCH 4/4 fsfreeze: add freeze fd ioctls
In reply to Fernando Luis Vazquez CaoAdds new ioctls (FS_FREEZE_FD, FS_THAW_FD, FS_ISFROZEN_FD) that operate on the freeze file descriptor; these can be used to freeze/thaw the filesystem and check the freeze state of the filesystem, thus avoiding the need to get new file descriptors constantly.
Additionaly, the argument of the ioctl FIGETFREEZEFD can now be used to indicate whether we want the filesystem frozen at fd creation time (a non-zero value means "freeze", 0 means "leave as is").
---
Documentation/ioctl/ioctl-number.txt +2 -0
@@ -301,6 +301,8 @@ Code Seq#(hex) Include File Comments <mailto:[email protected]> 0xAE all linux/kvm.h Kernel-based Virtual Machine <mailto:[email protected]> +0xAF 00-03 Filesystem freeze see fs/ioctl.c + <mailto:[email protected]> 0xB0 all RATIO devices in development: <mailto:[email protected]> 0xB1 00-1F PPPoX <mailto:[email protected]>
fs/ioctl.c +53 -5
104 lines not on this page · raw message
include/linux/fs.h +4 -0
@@ -328,6 +328,10 @@ struct inodes_stat_t {#define FIISFROZEN _IOR('X', 122, int)/* get sb freeze state */ #define FIGETFREEZEFD _IOWR('X', 123, int) +#define FS_FREEZE_FD _IOWR(0xAF, 1, int) +#define FS_THAW_FD _IOWR(0xAF, 2, int) +#define FS_ISFROZEN_FD _IOR(0xAF, 3, int) +#define FS_IOC_GETFLAGS _IOR('f', 1, long)#define FS_IOC_SETFLAGS _IOW('f', 2, long)#define FS_IOC_GETVERSION _IOR('v', 1, long)