diff options
Diffstat (limited to 'fs/ext4/super.c')
-rw-r--r-- | fs/ext4/super.c | 31 |
1 files changed, 7 insertions, 24 deletions
diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 2d51cd9af225..d76ec8277d3f 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c | |||
@@ -331,33 +331,17 @@ static void ext4_put_nojournal(handle_t *handle) | |||
331 | * journal_end calls result in the superblock being marked dirty, so | 331 | * journal_end calls result in the superblock being marked dirty, so |
332 | * that sync() will call the filesystem's write_super callback if | 332 | * that sync() will call the filesystem's write_super callback if |
333 | * appropriate. | 333 | * appropriate. |
334 | * | ||
335 | * To avoid j_barrier hold in userspace when a user calls freeze(), | ||
336 | * ext4 prevents a new handle from being started by s_frozen, which | ||
337 | * is in an upper layer. | ||
338 | */ | 334 | */ |
339 | handle_t *ext4_journal_start_sb(struct super_block *sb, int nblocks) | 335 | handle_t *ext4_journal_start_sb(struct super_block *sb, int nblocks) |
340 | { | 336 | { |
341 | journal_t *journal; | 337 | journal_t *journal; |
342 | handle_t *handle; | ||
343 | 338 | ||
344 | trace_ext4_journal_start(sb, nblocks, _RET_IP_); | 339 | trace_ext4_journal_start(sb, nblocks, _RET_IP_); |
345 | if (sb->s_flags & MS_RDONLY) | 340 | if (sb->s_flags & MS_RDONLY) |
346 | return ERR_PTR(-EROFS); | 341 | return ERR_PTR(-EROFS); |
347 | 342 | ||
343 | WARN_ON(sb->s_writers.frozen == SB_FREEZE_COMPLETE); | ||
348 | journal = EXT4_SB(sb)->s_journal; | 344 | journal = EXT4_SB(sb)->s_journal; |
349 | handle = ext4_journal_current_handle(); | ||
350 | |||
351 | /* | ||
352 | * If a handle has been started, it should be allowed to | ||
353 | * finish, otherwise deadlock could happen between freeze | ||
354 | * and others(e.g. truncate) due to the restart of the | ||
355 | * journal handle if the filesystem is forzen and active | ||
356 | * handles are not stopped. | ||
357 | */ | ||
358 | if (!handle) | ||
359 | vfs_check_frozen(sb, SB_FREEZE_TRANS); | ||
360 | |||
361 | if (!journal) | 345 | if (!journal) |
362 | return ext4_get_nojournal(); | 346 | return ext4_get_nojournal(); |
363 | /* | 347 | /* |
@@ -2747,6 +2731,7 @@ static int ext4_run_li_request(struct ext4_li_request *elr) | |||
2747 | sb = elr->lr_super; | 2731 | sb = elr->lr_super; |
2748 | ngroups = EXT4_SB(sb)->s_groups_count; | 2732 | ngroups = EXT4_SB(sb)->s_groups_count; |
2749 | 2733 | ||
2734 | sb_start_write(sb); | ||
2750 | for (group = elr->lr_next_group; group < ngroups; group++) { | 2735 | for (group = elr->lr_next_group; group < ngroups; group++) { |
2751 | gdp = ext4_get_group_desc(sb, group, NULL); | 2736 | gdp = ext4_get_group_desc(sb, group, NULL); |
2752 | if (!gdp) { | 2737 | if (!gdp) { |
@@ -2773,6 +2758,7 @@ static int ext4_run_li_request(struct ext4_li_request *elr) | |||
2773 | elr->lr_next_sched = jiffies + elr->lr_timeout; | 2758 | elr->lr_next_sched = jiffies + elr->lr_timeout; |
2774 | elr->lr_next_group = group + 1; | 2759 | elr->lr_next_group = group + 1; |
2775 | } | 2760 | } |
2761 | sb_end_write(sb); | ||
2776 | 2762 | ||
2777 | return ret; | 2763 | return ret; |
2778 | } | 2764 | } |
@@ -4460,10 +4446,8 @@ int ext4_force_commit(struct super_block *sb) | |||
4460 | return 0; | 4446 | return 0; |
4461 | 4447 | ||
4462 | journal = EXT4_SB(sb)->s_journal; | 4448 | journal = EXT4_SB(sb)->s_journal; |
4463 | if (journal) { | 4449 | if (journal) |
4464 | vfs_check_frozen(sb, SB_FREEZE_TRANS); | ||
4465 | ret = ext4_journal_force_commit(journal); | 4450 | ret = ext4_journal_force_commit(journal); |
4466 | } | ||
4467 | 4451 | ||
4468 | return ret; | 4452 | return ret; |
4469 | } | 4453 | } |
@@ -4493,9 +4477,8 @@ static int ext4_sync_fs(struct super_block *sb, int wait) | |||
4493 | * gives us a chance to flush the journal completely and mark the fs clean. | 4477 | * gives us a chance to flush the journal completely and mark the fs clean. |
4494 | * | 4478 | * |
4495 | * Note that only this function cannot bring a filesystem to be in a clean | 4479 | * Note that only this function cannot bring a filesystem to be in a clean |
4496 | * state independently, because ext4 prevents a new handle from being started | 4480 | * state independently. It relies on upper layer to stop all data & metadata |
4497 | * by @sb->s_frozen, which stays in an upper layer. It thus needs help from | 4481 | * modifications. |
4498 | * the upper layer. | ||
4499 | */ | 4482 | */ |
4500 | static int ext4_freeze(struct super_block *sb) | 4483 | static int ext4_freeze(struct super_block *sb) |
4501 | { | 4484 | { |
@@ -4522,7 +4505,7 @@ static int ext4_freeze(struct super_block *sb) | |||
4522 | EXT4_CLEAR_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER); | 4505 | EXT4_CLEAR_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER); |
4523 | error = ext4_commit_super(sb, 1); | 4506 | error = ext4_commit_super(sb, 1); |
4524 | out: | 4507 | out: |
4525 | /* we rely on s_frozen to stop further updates */ | 4508 | /* we rely on upper layer to stop further updates */ |
4526 | jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal); | 4509 | jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal); |
4527 | return error; | 4510 | return error; |
4528 | } | 4511 | } |