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); | ||
