diff options
-rw-r--r-- | fs/block_dev.c | 74 | ||||
-rw-r--r-- | fs/ioctl.c | 15 | ||||
-rw-r--r-- | fs/super.c | 90 | ||||
-rw-r--r-- | include/linux/fs.h | 2 |
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 | |||
326 | out_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) { |
333 | out_unlock: | 287 | bdev->bd_fsfreeze_count++; |
288 | mutex_unlock(&bdev->bd_fsfreeze_mutex); | ||
289 | return error; | ||
290 | } | ||
291 | out: | ||
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 | ||
539 | static int ioctl_fsthaw(struct file *filp) | 532 | static 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 | ||
945 | EXPORT_SYMBOL_GPL(vfs_kern_mount); | 945 | EXPORT_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 | */ | ||
955 | int 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 | } | ||
995 | EXPORT_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 | */ | ||
1003 | int 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 | |||
1027 | out: | ||
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 | } | ||
1035 | EXPORT_SYMBOL(thaw_super); | ||
1036 | |||
947 | static struct vfsmount *fs_set_subtype(struct vfsmount *mnt, const char *fstype) | 1037 | static 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 *); | |||
1797 | extern int iterate_mounts(int (*)(struct vfsmount *, void *), void *, | 1797 | extern int iterate_mounts(int (*)(struct vfsmount *, void *), void *, |
1798 | struct vfsmount *); | 1798 | struct vfsmount *); |
1799 | extern int vfs_statfs(struct dentry *, struct kstatfs *); | 1799 | extern int vfs_statfs(struct dentry *, struct kstatfs *); |
1800 | extern int freeze_super(struct super_block *super); | ||
1801 | extern int thaw_super(struct super_block *super); | ||
1800 | 1802 | ||
1801 | extern int current_umask(void); | 1803 | extern int current_umask(void); |
1802 | 1804 | ||