aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/block_dev.c74
-rw-r--r--fs/ioctl.c15
-rw-r--r--fs/super.c90
-rw-r--r--include/linux/fs.h2
4 files changed, 110 insertions, 71 deletions
diff --git a/fs/block_dev.c b/fs/block_dev.c
index 39cb6591d37d..1aba036dcabf 100644
--- a/fs/block_dev.c
+++ b/fs/block_dev.c
@@ -245,38 +245,14 @@ struct super_block *freeze_bdev(struct block_device *bdev)
245 sb = get_active_super(bdev); 245 sb = get_active_super(bdev);
246 if (!sb) 246 if (!sb)
247 goto out; 247 goto out;
248 down_write(&sb->s_umount); 248 error = freeze_super(sb);
249 if (sb->s_flags & MS_RDONLY) { 249 if (error) {
250 sb->s_frozen = SB_FREEZE_TRANS; 250 deactivate_super(sb);
251 up_write(&sb->s_umount); 251 bdev->bd_fsfreeze_count--;
252 mutex_unlock(&bdev->bd_fsfreeze_mutex); 252 mutex_unlock(&bdev->bd_fsfreeze_mutex);
253 return sb; 253 return ERR_PTR(error);
254 }
255
256 sb->s_frozen = SB_FREEZE_WRITE;
257 smp_wmb();
258
259 sync_filesystem(sb);
260
261 sb->s_frozen = SB_FREEZE_TRANS;
262 smp_wmb();
263
264 sync_blockdev(sb->s_bdev);
265
266 if (sb->s_op->freeze_fs) {
267 error = sb->s_op->freeze_fs(sb);
268 if (error) {
269 printk(KERN_ERR
270 "VFS:Filesystem freeze failed\n");
271 sb->s_frozen = SB_UNFROZEN;
272 deactivate_locked_super(sb);
273 bdev->bd_fsfreeze_count--;
274 mutex_unlock(&bdev->bd_fsfreeze_mutex);
275 return ERR_PTR(error);
276 }
277 } 254 }
278 up_write(&sb->s_umount); 255 deactivate_super(sb);
279
280 out: 256 out:
281 sync_blockdev(bdev); 257 sync_blockdev(bdev);
282 mutex_unlock(&bdev->bd_fsfreeze_mutex); 258 mutex_unlock(&bdev->bd_fsfreeze_mutex);
@@ -297,40 +273,22 @@ int thaw_bdev(struct block_device *bdev, struct super_block *sb)
297 273
298 mutex_lock(&bdev->bd_fsfreeze_mutex); 274 mutex_lock(&bdev->bd_fsfreeze_mutex);
299 if (!bdev->bd_fsfreeze_count) 275 if (!bdev->bd_fsfreeze_count)
300 goto out_unlock; 276 goto out;
301 277
302 error = 0; 278 error = 0;
303 if (--bdev->bd_fsfreeze_count > 0) 279 if (--bdev->bd_fsfreeze_count > 0)
304 goto out_unlock; 280 goto out;
305 281
306 if (!sb) 282 if (!sb)
307 goto out_unlock; 283 goto out;
308
309 BUG_ON(sb->s_bdev != bdev);
310 down_write(&sb->s_umount);
311 if (sb->s_flags & MS_RDONLY)
312 goto out_unfrozen;
313
314 if (sb->s_op->unfreeze_fs) {
315 error = sb->s_op->unfreeze_fs(sb);
316 if (error) {
317 printk(KERN_ERR
318 "VFS:Filesystem thaw failed\n");
319 sb->s_frozen = SB_FREEZE_TRANS;
320 bdev->bd_fsfreeze_count++;
321 mutex_unlock(&bdev->bd_fsfreeze_mutex);
322 return error;
323 }
324 }
325
326out_unfrozen:
327 sb->s_frozen = SB_UNFROZEN;
328 smp_wmb();
329 wake_up(&sb->s_wait_unfrozen);
330 284
331 if (sb) 285 error = thaw_super(sb);
332 deactivate_locked_super(sb); 286 if (error) {
333out_unlock: 287 bdev->bd_fsfreeze_count++;
288 mutex_unlock(&bdev->bd_fsfreeze_mutex);
289 return error;
290 }
291out:
334 mutex_unlock(&bdev->bd_fsfreeze_mutex); 292 mutex_unlock(&bdev->bd_fsfreeze_mutex);
335 return 0; 293 return 0;
336} 294}
diff --git a/fs/ioctl.c b/fs/ioctl.c
index 7faefb4da939..2d140a713861 100644
--- a/fs/ioctl.c
+++ b/fs/ioctl.c
@@ -525,15 +525,8 @@ static int ioctl_fsfreeze(struct file *filp)
525 if (sb->s_op->freeze_fs == NULL) 525 if (sb->s_op->freeze_fs == NULL)
526 return -EOPNOTSUPP; 526 return -EOPNOTSUPP;
527 527
528 /* If a blockdevice-backed filesystem isn't specified, return. */
529 if (sb->s_bdev == NULL)
530 return -EINVAL;
531
532 /* Freeze */ 528 /* Freeze */
533 sb = freeze_bdev(sb->s_bdev); 529 return freeze_super(sb);
534 if (IS_ERR(sb))
535 return PTR_ERR(sb);
536 return 0;
537} 530}
538 531
539static int ioctl_fsthaw(struct file *filp) 532static int ioctl_fsthaw(struct file *filp)
@@ -543,12 +536,8 @@ static int ioctl_fsthaw(struct file *filp)
543 if (!capable(CAP_SYS_ADMIN)) 536 if (!capable(CAP_SYS_ADMIN))
544 return -EPERM; 537 return -EPERM;
545 538
546 /* If a blockdevice-backed filesystem isn't specified, return EINVAL. */
547 if (sb->s_bdev == NULL)
548 return -EINVAL;
549
550 /* Thaw */ 539 /* Thaw */
551 return thaw_bdev(sb->s_bdev, sb); 540 return thaw_super(sb);
552} 541}
553 542
554/* 543/*
diff --git a/fs/super.c b/fs/super.c
index c248ac6a1a21..89afca5055ab 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -944,6 +944,96 @@ out:
944 944
945EXPORT_SYMBOL_GPL(vfs_kern_mount); 945EXPORT_SYMBOL_GPL(vfs_kern_mount);
946 946
947/**
948 * freeze_super -- lock the filesystem and force it into a consistent state
949 * @super: the super to lock
950 *
951 * Syncs the super to make sure the filesystem is consistent and calls the fs's
952 * freeze_fs. Subsequent calls to this without first thawing the fs will return
953 * -EBUSY.
954 */
955int freeze_super(struct super_block *sb)
956{
957 int ret;
958
959 atomic_inc(&sb->s_active);
960 down_write(&sb->s_umount);
961 if (sb->s_frozen) {
962 deactivate_locked_super(sb);
963 return -EBUSY;
964 }
965
966 if (sb->s_flags & MS_RDONLY) {
967 sb->s_frozen = SB_FREEZE_TRANS;
968 smp_wmb();
969 up_write(&sb->s_umount);
970 return 0;
971 }
972
973 sb->s_frozen = SB_FREEZE_WRITE;
974 smp_wmb();
975
976 sync_filesystem(sb);
977
978 sb->s_frozen = SB_FREEZE_TRANS;
979 smp_wmb();
980
981 sync_blockdev(sb->s_bdev);
982 if (sb->s_op->freeze_fs) {
983 ret = sb->s_op->freeze_fs(sb);
984 if (ret) {
985 printk(KERN_ERR
986 "VFS:Filesystem freeze failed\n");
987 sb->s_frozen = SB_UNFROZEN;
988 deactivate_locked_super(sb);
989 return ret;
990 }
991 }
992 up_write(&sb->s_umount);
993 return 0;
994}
995EXPORT_SYMBOL(freeze_super);
996
997/**
998 * thaw_super -- unlock filesystem
999 * @sb: the super to thaw
1000 *
1001 * Unlocks the filesystem and marks it writeable again after freeze_super().
1002 */
1003int thaw_super(struct super_block *sb)
1004{
1005 int error;
1006
1007 down_write(&sb->s_umount);
1008 if (sb->s_frozen == SB_UNFROZEN) {
1009 up_write(&sb->s_umount);
1010 return -EINVAL;
1011 }
1012
1013 if (sb->s_flags & MS_RDONLY)
1014 goto out;
1015
1016 if (sb->s_op->unfreeze_fs) {
1017 error = sb->s_op->unfreeze_fs(sb);
1018 if (error) {
1019 printk(KERN_ERR
1020 "VFS:Filesystem thaw failed\n");
1021 sb->s_frozen = SB_FREEZE_TRANS;
1022 up_write(&sb->s_umount);
1023 return error;
1024 }
1025 }
1026
1027out:
1028 sb->s_frozen = SB_UNFROZEN;
1029 smp_wmb();
1030 wake_up(&sb->s_wait_unfrozen);
1031 deactivate_locked_super(sb);
1032
1033 return 0;
1034}
1035EXPORT_SYMBOL(thaw_super);
1036
947static struct vfsmount *fs_set_subtype(struct vfsmount *mnt, const char *fstype) 1037static struct vfsmount *fs_set_subtype(struct vfsmount *mnt, const char *fstype)
948{ 1038{
949 int err; 1039 int err;
diff --git a/include/linux/fs.h b/include/linux/fs.h
index eeb04ba17b63..d51256bc6328 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1797,6 +1797,8 @@ extern void drop_collected_mounts(struct vfsmount *);
1797extern int iterate_mounts(int (*)(struct vfsmount *, void *), void *, 1797extern int iterate_mounts(int (*)(struct vfsmount *, void *), void *,
1798 struct vfsmount *); 1798 struct vfsmount *);
1799extern int vfs_statfs(struct dentry *, struct kstatfs *); 1799extern int vfs_statfs(struct dentry *, struct kstatfs *);
1800extern int freeze_super(struct super_block *super);
1801extern int thaw_super(struct super_block *super);
1800 1802
1801extern int current_umask(void); 1803extern int current_umask(void);
1802 1804