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 d8759401ecae..9cc9bfd5176b 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c | |||
@@ -332,33 +332,17 @@ static void ext4_put_nojournal(handle_t *handle) | |||
332 | * journal_end calls result in the superblock being marked dirty, so | 332 | * journal_end calls result in the superblock being marked dirty, so |
333 | * that sync() will call the filesystem's write_super callback if | 333 | * that sync() will call the filesystem's write_super callback if |
334 | * appropriate. | 334 | * appropriate. |
335 | * | ||
336 | * To avoid j_barrier hold in userspace when a user calls freeze(), | ||
337 | * ext4 prevents a new handle from being started by s_frozen, which | ||
338 | * is in an upper layer. | ||
339 | */ | 335 | */ |
340 | handle_t *ext4_journal_start_sb(struct super_block *sb, int nblocks) | 336 | handle_t *ext4_journal_start_sb(struct super_block *sb, int nblocks) |
341 | { | 337 | { |
342 | journal_t *journal; | 338 | journal_t *journal; |
343 | handle_t *handle; | ||
344 | 339 | ||
345 | trace_ext4_journal_start(sb, nblocks, _RET_IP_); | 340 | trace_ext4_journal_start(sb, nblocks, _RET_IP_); |
346 | if (sb->s_flags & MS_RDONLY) | 341 | if (sb->s_flags & MS_RDONLY) |
347 | return ERR_PTR(-EROFS); | 342 | return ERR_PTR(-EROFS); |
348 | 343 | ||
344 | WARN_ON(sb->s_writers.frozen == SB_FREEZE_COMPLETE); | ||
349 | journal = EXT4_SB(sb)->s_journal; | 345 | journal = EXT4_SB(sb)->s_journal; |
350 | handle = ext4_journal_current_handle(); | ||
351 | |||
352 | /* | ||
353 | * If a handle has been started, it should be allowed to | ||
354 | * finish, otherwise deadlock could happen between freeze | ||
355 | * and others(e.g. truncate) due to the restart of the | ||
356 | * journal handle if the filesystem is forzen and active | ||
357 | * handles are not stopped. | ||
358 | */ | ||
359 | if (!handle) | ||
360 | vfs_check_frozen(sb, SB_FREEZE_TRANS); | ||
361 | |||
362 | if (!journal) | 346 | if (!journal) |
363 | return ext4_get_nojournal(); | 347 | return ext4_get_nojournal(); |
364 | /* | 348 | /* |
@@ -2723,6 +2707,7 @@ static int ext4_run_li_request(struct ext4_li_request *elr) | |||
2723 | sb = elr->lr_super; | 2707 | sb = elr->lr_super; |
2724 | ngroups = EXT4_SB(sb)->s_groups_count; | 2708 | ngroups = EXT4_SB(sb)->s_groups_count; |
2725 | 2709 | ||
2710 | sb_start_write(sb); | ||
2726 | for (group = elr->lr_next_group; group < ngroups; group++) { | 2711 | for (group = elr->lr_next_group; group < ngroups; group++) { |
2727 | gdp = ext4_get_group_desc(sb, group, NULL); | 2712 | gdp = ext4_get_group_desc(sb, group, NULL); |
2728 | if (!gdp) { | 2713 | if (!gdp) { |
@@ -2749,6 +2734,7 @@ static int ext4_run_li_request(struct ext4_li_request *elr) | |||
2749 | elr->lr_next_sched = jiffies + elr->lr_timeout; | 2734 | elr->lr_next_sched = jiffies + elr->lr_timeout; |
2750 | elr->lr_next_group = group + 1; | 2735 | elr->lr_next_group = group + 1; |
2751 | } | 2736 | } |
2737 | sb_end_write(sb); | ||
2752 | 2738 | ||
2753 | return ret; | 2739 | return ret; |
2754 | } | 2740 | } |
@@ -4302,10 +4288,8 @@ int ext4_force_commit(struct super_block *sb) | |||
4302 | return 0; | 4288 | return 0; |
4303 | 4289 | ||
4304 | journal = EXT4_SB(sb)->s_journal; | 4290 | journal = EXT4_SB(sb)->s_journal; |
4305 | if (journal) { | 4291 | if (journal) |
4306 | vfs_check_frozen(sb, SB_FREEZE_TRANS); | ||
4307 | ret = ext4_journal_force_commit(journal); | 4292 | ret = ext4_journal_force_commit(journal); |
4308 | } | ||
4309 | 4293 | ||
4310 | return ret; | 4294 | return ret; |
4311 | } | 4295 | } |
@@ -4342,9 +4326,8 @@ static int ext4_sync_fs(struct super_block *sb, int wait) | |||
4342 | * gives us a chance to flush the journal completely and mark the fs clean. | 4326 | * gives us a chance to flush the journal completely and mark the fs clean. |
4343 | * | 4327 | * |
4344 | * Note that only this function cannot bring a filesystem to be in a clean | 4328 | * Note that only this function cannot bring a filesystem to be in a clean |
4345 | * state independently, because ext4 prevents a new handle from being started | 4329 | * state independently. It relies on upper layer to stop all data & metadata |
4346 | * by @sb->s_frozen, which stays in an upper layer. It thus needs help from | 4330 | * modifications. |
4347 | * the upper layer. | ||
4348 | */ | 4331 | */ |
4349 | static int ext4_freeze(struct super_block *sb) | 4332 | static int ext4_freeze(struct super_block *sb) |
4350 | { | 4333 | { |
@@ -4371,7 +4354,7 @@ static int ext4_freeze(struct super_block *sb) | |||
4371 | EXT4_CLEAR_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER); | 4354 | EXT4_CLEAR_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER); |
4372 | error = ext4_commit_super(sb, 1); | 4355 | error = ext4_commit_super(sb, 1); |
4373 | out: | 4356 | out: |
4374 | /* we rely on s_frozen to stop further updates */ | 4357 | /* we rely on upper layer to stop further updates */ |
4375 | jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal); | 4358 | jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal); |
4376 | return error; | 4359 | return error; |
4377 | } | 4360 | } |