aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJan Kara <jack@suse.cz>2012-06-12 10:20:38 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2012-07-31 01:45:48 -0400
commit8e8ad8a57c75f3bda2d03a4c4396a9a7024ad275 (patch)
tree8d1fd1d0f296d2a2977b54dee5740d855dfa031e
parent14da9200140f8d722ad1767dfabadebd8b34f2ad (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.c15
-rw-r--r--fs/ext4/mmp.c6
-rw-r--r--fs/ext4/super.c31
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;
305no_delete: 313no_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:
4773out_ret: 4777out_ret:
4774 ret = block_page_mkwrite_return(ret); 4778 ret = block_page_mkwrite_return(ret);
4775out: 4779out:
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 */
340handle_t *ext4_journal_start_sb(struct super_block *sb, int nblocks) 336handle_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 */
4349static int ext4_freeze(struct super_block *sb) 4332static 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);
4373out: 4356out:
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}