Adds 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"). Signed-off-by: Fernando Luis Vazquez Cao <fernando@xxxxxxxxxxxxx> --- diff -urNp linux-3.0-orig/Documentation/ioctl/ioctl-number.txt linux-3.0/Documentation/ioctl/ioctl-number.txt --- linux-3.0-orig/Documentation/ioctl/ioctl-number.txt 2011-07-22 11:17:23.000000000 +0900 +++ linux-3.0/Documentation/ioctl/ioctl-number.txt 2011-07-27 15:13:45.583998849 +0900 @@ -301,6 +301,8 @@ Code Seq#(hex) Include File Comments <mailto:rusty@xxxxxxxxxxxxxxx> 0xAE all linux/kvm.h Kernel-based Virtual Machine <mailto:kvm@xxxxxxxxxxxxxxx> +0xAF 00-03 Filesystem freeze see fs/ioctl.c + <mailto:linux-fsdevel@xxxxxxxxxxxxxxx> 0xB0 all RATIO devices in development: <mailto:vgo@xxxxxxxx> 0xB1 00-1F PPPoX <mailto:mostrows@xxxxxxxxxxxxxxxxx> diff -urNp linux-3.0-orig/fs/ioctl.c linux-3.0/fs/ioctl.c --- linux-3.0-orig/fs/ioctl.c 2011-07-27 15:12:22.876000730 +0900 +++ linux-3.0/fs/ioctl.c 2011-07-27 15:46:57.923998173 +0900 @@ -528,14 +528,48 @@ static int ioctl_fsfreeze(struct file *f struct freeze_fd_data { struct super_block *sb; + int thaw_pending; }; +static long freeze_fd_ioctl(struct file *filp, + unsigned int ioctl, unsigned long arg) +{ + struct freeze_fd_data *fd_data = filp->private_data; + struct super_block *sb = fd_data->sb; + int error = 0; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + switch (ioctl) { + case FS_FREEZE_FD: + error = freeze_super(sb); + if (!error) + fd_data->thaw_pending++; + break; + case FS_THAW_FD: + error = thaw_super(sb); + if (!error) + fd_data->thaw_pending--; + break; + case FS_ISFROZEN_FD: + error = isfrozen_super(sb); + if (error >= 0) + return put_user(error, (int __user *)arg); + break; + default: + error = -EINVAL; + } + return error; +} + static int freeze_fd_release(struct inode *inode, struct file *filp) { struct freeze_fd_data *fd_data = filp->private_data; struct super_block *sb = fd_data->sb; - thaw_super(sb); + if (fd_data->thaw_pending) + thaw_super(sb); deactivate_super(sb); kfree(fd_data); @@ -544,19 +578,25 @@ static int freeze_fd_release(struct inod static struct file_operations freeze_fd_fops = { .release = freeze_fd_release, + .unlocked_ioctl = freeze_fd_ioctl, + .compat_ioctl = freeze_fd_ioctl, .llseek = noop_llseek, }; static int ioctl_get_freeze_fd(struct file *filp, int __user *argp) { struct super_block *sb = filp->f_path.dentry->d_inode->i_sb; - int fd, ret; + int fd, ret, should_freeze; struct file *file; struct freeze_fd_data *fd_data; if (!capable(CAP_SYS_ADMIN)) return -EPERM; + ret = get_user(should_freeze, argp); + if (ret) + return ret; + /* If filesystem doesn't support freeze feature, return. */ if (sb->s_op->freeze_fs == NULL) return -EOPNOTSUPP; @@ -571,6 +611,7 @@ static int ioctl_get_freeze_fd(struct fi goto err_free_fd_data; fd = ret; fd_data->sb = sb; + fd_data->thaw_pending = 0; file = anon_inode_getfile("freeze-fd", &freeze_fd_fops, fd_data, O_RDWR); if (IS_ERR(file)) { @@ -580,12 +621,19 @@ static int ioctl_get_freeze_fd(struct fi /* Increment the active counter to keep the superblock around * until the freeze fd is closed. + * + * When should_freeze is set freeze_super() is called which takes an + * active reference to the superblock. However that reference could be + * released through ioctl_fsthaw, so we still need to take our own here. */ atomic_inc(&sb->s_active); - ret = freeze_super(sb); - if (ret < 0) - goto err_deact_super; + if (should_freeze) { + ret = freeze_super(sb); + if (ret < 0) + goto err_deact_super; + fd_data->thaw_pending++; + } fd_install(fd, file); diff -urNp linux-3.0-orig/include/linux/fs.h linux-3.0/include/linux/fs.h --- linux-3.0-orig/include/linux/fs.h 2011-07-27 15:12:22.876000730 +0900 +++ linux-3.0/include/linux/fs.h 2011-07-27 15:13:45.587999047 +0900 @@ -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) -- 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