diff options
author | Jan Kara <jack@suse.cz> | 2012-06-12 10:20:38 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2012-07-31 01:45:48 -0400 |
commit | 8e8ad8a57c75f3bda2d03a4c4396a9a7024ad275 (patch) | |
tree | 8d1fd1d0f296d2a2977b54dee5740d855dfa031e | |
parent | 14da9200140f8d722ad1767dfabadebd8b34f2ad (diff) |
ext4: Convert to new freezing mechanism
We remove most of frozen checks since upper layer takes care of blocking all
writes. We have to handle protection in ext4_page_mkwrite() in a special way
because we cannot use generic block_page_mkwrite(). Also we add a freeze
protection to ext4_evict_inode() so that iput() of unlinked inode cannot modify
a frozen filesystem (we cannot easily instrument ext4_journal_start() /
ext4_journal_stop() with freeze protection because we are missing the
superblock pointer in ext4_journal_stop() in nojournal mode).
CC: linux-ext4@vger.kernel.org
CC: "Theodore Ts'o" <tytso@mit.edu>
BugLink: https://bugs.launchpad.net/bugs/897421
Tested-by: Kamal Mostafa <kamal@canonical.com>
Tested-by: Peter M. Petrakis <peter.petrakis@canonical.com>
Tested-by: Dann Frazier <dann.frazier@canonical.com>
Tested-by: Massimo Morana <massimo.morana@canonical.com>
Acked-by: "Theodore Ts'o" <tytso@mit.edu>
Signed-off-by: Jan Kara <jack@suse.cz>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r-- | fs/ext4/inode.c | 15 | ||||
-rw-r--r-- | fs/ext4/mmp.c | 6 | ||||
-rw-r--r-- | fs/ext4/super.c | 31 |
3 files changed, 23 insertions, 29 deletions
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 02bc8cbe7281..301e1c2db891 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c | |||
@@ -233,6 +233,11 @@ void ext4_evict_inode(struct inode *inode) | |||
233 | if (is_bad_inode(inode)) | 233 | if (is_bad_inode(inode)) |
234 | goto no_delete; | 234 | goto no_delete; |
235 | 235 | ||
236 | /* | ||
237 | * Protect us against freezing - iput() caller didn't have to have any | ||
238 | * protection against it | ||
239 | */ | ||
240 | sb_start_intwrite(inode->i_sb); | ||
236 | handle = ext4_journal_start(inode, ext4_blocks_for_truncate(inode)+3); | 241 | handle = ext4_journal_start(inode, ext4_blocks_for_truncate(inode)+3); |
237 | if (IS_ERR(handle)) { | 242 | if (IS_ERR(handle)) { |
238 | ext4_std_error(inode->i_sb, PTR_ERR(handle)); | 243 | ext4_std_error(inode->i_sb, PTR_ERR(handle)); |
@@ -242,6 +247,7 @@ void ext4_evict_inode(struct inode *inode) | |||
242 | * cleaned up. | 247 | * cleaned up. |
243 | */ | 248 | */ |
244 | ext4_orphan_del(NULL, inode); | 249 | ext4_orphan_del(NULL, inode); |
250 | sb_end_intwrite(inode->i_sb); | ||
245 | goto no_delete; | 251 | goto no_delete; |
246 | } | 252 | } |
247 | 253 | ||
@@ -273,6 +279,7 @@ void ext4_evict_inode(struct inode *inode) | |||
273 | stop_handle: | 279 | stop_handle: |
274 | ext4_journal_stop(handle); | 280 | ext4_journal_stop(handle); |
275 | ext4_orphan_del(NULL, inode); | 281 | ext4_orphan_del(NULL, inode); |
282 | sb_end_intwrite(inode->i_sb); | ||
276 | goto no_delete; | 283 | goto no_delete; |
277 | } | 284 | } |
278 | } | 285 | } |
@@ -301,6 +308,7 @@ void ext4_evict_inode(struct inode *inode) | |||
301 | else | 308 | else |
302 | ext4_free_inode(handle, inode); | 309 | ext4_free_inode(handle, inode); |
303 | ext4_journal_stop(handle); | 310 | ext4_journal_stop(handle); |
311 | sb_end_intwrite(inode->i_sb); | ||
304 | return; | 312 | return; |
305 | no_delete: | 313 | no_delete: |
306 | ext4_clear_inode(inode); /* We must guarantee clearing of inode... */ | 314 | ext4_clear_inode(inode); /* We must guarantee clearing of inode... */ |
@@ -4701,11 +4709,7 @@ int ext4_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) | |||
4701 | get_block_t *get_block; | 4709 | get_block_t *get_block; |
4702 | int retries = 0; | 4710 | int retries = 0; |
4703 | 4711 | ||
4704 | /* | 4712 | sb_start_pagefault(inode->i_sb); |
4705 | * This check is racy but catches the common case. We rely on | ||
4706 | * __block_page_mkwrite() to do a reliable check. | ||
4707 | */ | ||
4708 | vfs_check_frozen(inode->i_sb, SB_FREEZE_WRITE); | ||
4709 | /* Delalloc case is easy... */ | 4713 | /* Delalloc case is easy... */ |
4710 | if (test_opt(inode->i_sb, DELALLOC) && | 4714 | if (test_opt(inode->i_sb, DELALLOC) && |
4711 | !ext4_should_journal_data(inode) && | 4715 | !ext4_should_journal_data(inode) && |
@@ -4773,5 +4777,6 @@ retry_alloc: | |||
4773 | out_ret: | 4777 | out_ret: |
4774 | ret = block_page_mkwrite_return(ret); | 4778 | ret = block_page_mkwrite_return(ret); |
4775 | out: | 4779 | out: |
4780 | sb_end_pagefault(inode->i_sb); | ||
4776 | return ret; | 4781 | return ret; |
4777 | } | 4782 | } |
diff --git a/fs/ext4/mmp.c b/fs/ext4/mmp.c index f99a1311e847..fe7c63f4717e 100644 --- a/fs/ext4/mmp.c +++ b/fs/ext4/mmp.c | |||
@@ -44,6 +44,11 @@ static int write_mmp_block(struct super_block *sb, struct buffer_head *bh) | |||
44 | { | 44 | { |
45 | struct mmp_struct *mmp = (struct mmp_struct *)(bh->b_data); | 45 | struct mmp_struct *mmp = (struct mmp_struct *)(bh->b_data); |
46 | 46 | ||
47 | /* | ||
48 | * We protect against freezing so that we don't create dirty buffers | ||
49 | * on frozen filesystem. | ||
50 | */ | ||
51 | sb_start_write(sb); | ||
47 | ext4_mmp_csum_set(sb, mmp); | 52 | ext4_mmp_csum_set(sb, mmp); |
48 | mark_buffer_dirty(bh); | 53 | mark_buffer_dirty(bh); |
49 | lock_buffer(bh); | 54 | lock_buffer(bh); |
@@ -51,6 +56,7 @@ static int write_mmp_block(struct super_block *sb, struct buffer_head *bh) | |||
51 | get_bh(bh); | 56 | get_bh(bh); |
52 | submit_bh(WRITE_SYNC, bh); | 57 | submit_bh(WRITE_SYNC, bh); |
53 | wait_on_buffer(bh); | 58 | wait_on_buffer(bh); |
59 | sb_end_write(sb); | ||
54 | if (unlikely(!buffer_uptodate(bh))) | 60 | if (unlikely(!buffer_uptodate(bh))) |
55 | return 1; | 61 | return 1; |
56 | 62 | ||
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 | } |