aboutsummaryrefslogtreecommitdiffstats
path: root/fs/block_dev.c
diff options
context:
space:
mode:
authorJosef Bacik <josef@redhat.com>2010-03-23 10:34:56 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2010-05-21 18:31:18 -0400
commit18e9e5104fcd9a973ffe3eed3816c87f2a1b6cd2 (patch)
tree635369c866fcb384223618c878e0b4c317790634 /fs/block_dev.c
parente1e46bf1866317d4f86f66bf18d3f07317d9f9ee (diff)
Introduce freeze_super and thaw_super for the fsfreeze ioctl
Currently the way we do freezing is by passing sb>s_bdev to freeze_bdev and then letting it do all the work. But freezing is more of an fs thing, and doesn't really have much to do with the bdev at all, all the work gets done with the super. In btrfs we do not populate s_bdev, since we can have multiple bdev's for one fs and setting s_bdev makes removing devices from a pool kind of tricky. This means that freezing a btrfs filesystem fails, which causes us to corrupt with things like tux-on-ice which use the fsfreeze mechanism. So instead of populating sb->s_bdev with a random bdev in our pool, I've broken the actual fs freezing stuff into freeze_super and thaw_super. These just take the super_block that we're freezing and does the appropriate work. It's basically just copy and pasted from freeze_bdev. I've then converted freeze_bdev over to use the new super helpers. I've tested this with ext4 and btrfs and verified everything continues to work the same as before. The only new gotcha is multiple calls to the fsfreeze ioctl will return EBUSY if the fs is already frozen. I thought this was a better solution than adding a freeze counter to the super_block, but if everybody hates this idea I'm open to suggestions. Thanks, Signed-off-by: Josef Bacik <josef@redhat.com> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/block_dev.c')
-rw-r--r--fs/block_dev.c74
1 files changed, 16 insertions, 58 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}