diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-04-11 18:45:47 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-04-11 18:45:47 -0400 |
| commit | a97b52022a73ec12e43f0b2c7d4bd1f40f89c81d (patch) | |
| tree | 1a35544915a5704fa59c63b43e9f46e20be1e296 | |
| parent | 18770c7c3a0ccd60017ac76b5d2e7d1f71376b94 (diff) | |
| parent | c8205636029fc869278c55b7336053b3e7ae3ef4 (diff) | |
Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4
* 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4:
ext4: fix data corruption regression by reverting commit 6de9843dab3f
ext4: Allow indirect-block file to grow the file size to max file size
ext4: allow an active handle to be started when freezing
ext4: sync the directory inode in ext4_sync_parent()
ext4: init timer earlier to avoid a kernel panic in __save_error_info
jbd2: fix potential memory leak on transaction commit
ext4: fix a double free in ext4_register_li_request
ext4: fix credits computing for indirect mapped files
ext4: remove unnecessary [cm]time update of quota file
jbd2: move bdget out of critical section
| -rw-r--r-- | fs/ext4/ext4_jbd2.h | 4 | ||||
| -rw-r--r-- | fs/ext4/fsync.c | 17 | ||||
| -rw-r--r-- | fs/ext4/inode.c | 35 | ||||
| -rw-r--r-- | fs/ext4/super.c | 74 | ||||
| -rw-r--r-- | fs/jbd2/commit.c | 4 | ||||
| -rw-r--r-- | fs/jbd2/journal.c | 3 |
6 files changed, 102 insertions, 35 deletions
diff --git a/fs/ext4/ext4_jbd2.h b/fs/ext4/ext4_jbd2.h index e25e99bf7ee..d0f53538a57 100644 --- a/fs/ext4/ext4_jbd2.h +++ b/fs/ext4/ext4_jbd2.h | |||
| @@ -86,8 +86,8 @@ | |||
| 86 | 86 | ||
| 87 | #ifdef CONFIG_QUOTA | 87 | #ifdef CONFIG_QUOTA |
| 88 | /* Amount of blocks needed for quota update - we know that the structure was | 88 | /* Amount of blocks needed for quota update - we know that the structure was |
| 89 | * allocated so we need to update only inode+data */ | 89 | * allocated so we need to update only data block */ |
| 90 | #define EXT4_QUOTA_TRANS_BLOCKS(sb) (test_opt(sb, QUOTA) ? 2 : 0) | 90 | #define EXT4_QUOTA_TRANS_BLOCKS(sb) (test_opt(sb, QUOTA) ? 1 : 0) |
| 91 | /* Amount of blocks needed for quota insert/delete - we do some block writes | 91 | /* Amount of blocks needed for quota insert/delete - we do some block writes |
| 92 | * but inode, sb and group updates are done only once */ | 92 | * but inode, sb and group updates are done only once */ |
| 93 | #define EXT4_QUOTA_INIT_BLOCKS(sb) (test_opt(sb, QUOTA) ? (DQUOT_INIT_ALLOC*\ | 93 | #define EXT4_QUOTA_INIT_BLOCKS(sb) (test_opt(sb, QUOTA) ? (DQUOT_INIT_ALLOC*\ |
diff --git a/fs/ext4/fsync.c b/fs/ext4/fsync.c index 4673bc05274..e9473cbe80d 100644 --- a/fs/ext4/fsync.c +++ b/fs/ext4/fsync.c | |||
| @@ -125,9 +125,11 @@ extern int ext4_flush_completed_IO(struct inode *inode) | |||
| 125 | * the parent directory's parent as well, and so on recursively, if | 125 | * the parent directory's parent as well, and so on recursively, if |
| 126 | * they are also freshly created. | 126 | * they are also freshly created. |
| 127 | */ | 127 | */ |
| 128 | static void ext4_sync_parent(struct inode *inode) | 128 | static int ext4_sync_parent(struct inode *inode) |
| 129 | { | 129 | { |
| 130 | struct writeback_control wbc; | ||
| 130 | struct dentry *dentry = NULL; | 131 | struct dentry *dentry = NULL; |
| 132 | int ret = 0; | ||
| 131 | 133 | ||
| 132 | while (inode && ext4_test_inode_state(inode, EXT4_STATE_NEWENTRY)) { | 134 | while (inode && ext4_test_inode_state(inode, EXT4_STATE_NEWENTRY)) { |
| 133 | ext4_clear_inode_state(inode, EXT4_STATE_NEWENTRY); | 135 | ext4_clear_inode_state(inode, EXT4_STATE_NEWENTRY); |
| @@ -136,8 +138,17 @@ static void ext4_sync_parent(struct inode *inode) | |||
| 136 | if (!dentry || !dentry->d_parent || !dentry->d_parent->d_inode) | 138 | if (!dentry || !dentry->d_parent || !dentry->d_parent->d_inode) |
| 137 | break; | 139 | break; |
| 138 | inode = dentry->d_parent->d_inode; | 140 | inode = dentry->d_parent->d_inode; |
| 139 | sync_mapping_buffers(inode->i_mapping); | 141 | ret = sync_mapping_buffers(inode->i_mapping); |
| 142 | if (ret) | ||
| 143 | break; | ||
| 144 | memset(&wbc, 0, sizeof(wbc)); | ||
| 145 | wbc.sync_mode = WB_SYNC_ALL; | ||
| 146 | wbc.nr_to_write = 0; /* only write out the inode */ | ||
| 147 | ret = sync_inode(inode, &wbc); | ||
| 148 | if (ret) | ||
| 149 | break; | ||
| 140 | } | 150 | } |
| 151 | return ret; | ||
| 141 | } | 152 | } |
| 142 | 153 | ||
| 143 | /* | 154 | /* |
| @@ -176,7 +187,7 @@ int ext4_sync_file(struct file *file, int datasync) | |||
| 176 | if (!journal) { | 187 | if (!journal) { |
| 177 | ret = generic_file_fsync(file, datasync); | 188 | ret = generic_file_fsync(file, datasync); |
| 178 | if (!ret && !list_empty(&inode->i_dentry)) | 189 | if (!ret && !list_empty(&inode->i_dentry)) |
| 179 | ext4_sync_parent(inode); | 190 | ret = ext4_sync_parent(inode); |
| 180 | goto out; | 191 | goto out; |
| 181 | } | 192 | } |
| 182 | 193 | ||
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index ad8e303c0d2..f2fa5e8a582 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c | |||
| @@ -2502,6 +2502,7 @@ static int ext4_da_get_block_prep(struct inode *inode, sector_t iblock, | |||
| 2502 | * for partial write. | 2502 | * for partial write. |
| 2503 | */ | 2503 | */ |
| 2504 | set_buffer_new(bh); | 2504 | set_buffer_new(bh); |
| 2505 | set_buffer_mapped(bh); | ||
| 2505 | } | 2506 | } |
| 2506 | return 0; | 2507 | return 0; |
| 2507 | } | 2508 | } |
| @@ -4429,8 +4430,8 @@ void ext4_truncate(struct inode *inode) | |||
| 4429 | Indirect chain[4]; | 4430 | Indirect chain[4]; |
| 4430 | Indirect *partial; | 4431 | Indirect *partial; |
| 4431 | __le32 nr = 0; | 4432 | __le32 nr = 0; |
| 4432 | int n; | 4433 | int n = 0; |
| 4433 | ext4_lblk_t last_block; | 4434 | ext4_lblk_t last_block, max_block; |
| 4434 | unsigned blocksize = inode->i_sb->s_blocksize; | 4435 | unsigned blocksize = inode->i_sb->s_blocksize; |
| 4435 | 4436 | ||
| 4436 | trace_ext4_truncate_enter(inode); | 4437 | trace_ext4_truncate_enter(inode); |
| @@ -4455,14 +4456,18 @@ void ext4_truncate(struct inode *inode) | |||
| 4455 | 4456 | ||
| 4456 | last_block = (inode->i_size + blocksize-1) | 4457 | last_block = (inode->i_size + blocksize-1) |
| 4457 | >> EXT4_BLOCK_SIZE_BITS(inode->i_sb); | 4458 | >> EXT4_BLOCK_SIZE_BITS(inode->i_sb); |
| 4459 | max_block = (EXT4_SB(inode->i_sb)->s_bitmap_maxbytes + blocksize-1) | ||
| 4460 | >> EXT4_BLOCK_SIZE_BITS(inode->i_sb); | ||
| 4458 | 4461 | ||
| 4459 | if (inode->i_size & (blocksize - 1)) | 4462 | if (inode->i_size & (blocksize - 1)) |
| 4460 | if (ext4_block_truncate_page(handle, mapping, inode->i_size)) | 4463 | if (ext4_block_truncate_page(handle, mapping, inode->i_size)) |
| 4461 | goto out_stop; | 4464 | goto out_stop; |
| 4462 | 4465 | ||
| 4463 | n = ext4_block_to_path(inode, last_block, offsets, NULL); | 4466 | if (last_block != max_block) { |
| 4464 | if (n == 0) | 4467 | n = ext4_block_to_path(inode, last_block, offsets, NULL); |
| 4465 | goto out_stop; /* error */ | 4468 | if (n == 0) |
| 4469 | goto out_stop; /* error */ | ||
| 4470 | } | ||
| 4466 | 4471 | ||
| 4467 | /* | 4472 | /* |
| 4468 | * OK. This truncate is going to happen. We add the inode to the | 4473 | * OK. This truncate is going to happen. We add the inode to the |
| @@ -4493,7 +4498,13 @@ void ext4_truncate(struct inode *inode) | |||
| 4493 | */ | 4498 | */ |
| 4494 | ei->i_disksize = inode->i_size; | 4499 | ei->i_disksize = inode->i_size; |
| 4495 | 4500 | ||
| 4496 | if (n == 1) { /* direct blocks */ | 4501 | if (last_block == max_block) { |
| 4502 | /* | ||
| 4503 | * It is unnecessary to free any data blocks if last_block is | ||
| 4504 | * equal to the indirect block limit. | ||
| 4505 | */ | ||
| 4506 | goto out_unlock; | ||
| 4507 | } else if (n == 1) { /* direct blocks */ | ||
| 4497 | ext4_free_data(handle, inode, NULL, i_data+offsets[0], | 4508 | ext4_free_data(handle, inode, NULL, i_data+offsets[0], |
| 4498 | i_data + EXT4_NDIR_BLOCKS); | 4509 | i_data + EXT4_NDIR_BLOCKS); |
| 4499 | goto do_indirects; | 4510 | goto do_indirects; |
| @@ -4553,6 +4564,7 @@ do_indirects: | |||
| 4553 | ; | 4564 | ; |
| 4554 | } | 4565 | } |
| 4555 | 4566 | ||
| 4567 | out_unlock: | ||
| 4556 | up_write(&ei->i_data_sem); | 4568 | up_write(&ei->i_data_sem); |
| 4557 | inode->i_mtime = inode->i_ctime = ext4_current_time(inode); | 4569 | inode->i_mtime = inode->i_ctime = ext4_current_time(inode); |
| 4558 | ext4_mark_inode_dirty(handle, inode); | 4570 | ext4_mark_inode_dirty(handle, inode); |
| @@ -5398,13 +5410,12 @@ static int ext4_indirect_trans_blocks(struct inode *inode, int nrblocks, | |||
| 5398 | /* if nrblocks are contiguous */ | 5410 | /* if nrblocks are contiguous */ |
| 5399 | if (chunk) { | 5411 | if (chunk) { |
| 5400 | /* | 5412 | /* |
| 5401 | * With N contiguous data blocks, it need at most | 5413 | * With N contiguous data blocks, we need at most |
| 5402 | * N/EXT4_ADDR_PER_BLOCK(inode->i_sb) indirect blocks | 5414 | * N/EXT4_ADDR_PER_BLOCK(inode->i_sb) + 1 indirect blocks, |
| 5403 | * 2 dindirect blocks | 5415 | * 2 dindirect blocks, and 1 tindirect block |
| 5404 | * 1 tindirect block | ||
| 5405 | */ | 5416 | */ |
| 5406 | indirects = nrblocks / EXT4_ADDR_PER_BLOCK(inode->i_sb); | 5417 | return DIV_ROUND_UP(nrblocks, |
| 5407 | return indirects + 3; | 5418 | EXT4_ADDR_PER_BLOCK(inode->i_sb)) + 4; |
| 5408 | } | 5419 | } |
| 5409 | /* | 5420 | /* |
| 5410 | * if nrblocks are not contiguous, worse case, each block touch | 5421 | * if nrblocks are not contiguous, worse case, each block touch |
diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 056474b7b8e..8553dfb310a 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c | |||
| @@ -242,27 +242,44 @@ static void ext4_put_nojournal(handle_t *handle) | |||
| 242 | * journal_end calls result in the superblock being marked dirty, so | 242 | * journal_end calls result in the superblock being marked dirty, so |
| 243 | * that sync() will call the filesystem's write_super callback if | 243 | * that sync() will call the filesystem's write_super callback if |
| 244 | * appropriate. | 244 | * appropriate. |
| 245 | * | ||
| 246 | * To avoid j_barrier hold in userspace when a user calls freeze(), | ||
| 247 | * ext4 prevents a new handle from being started by s_frozen, which | ||
| 248 | * is in an upper layer. | ||
| 245 | */ | 249 | */ |
| 246 | handle_t *ext4_journal_start_sb(struct super_block *sb, int nblocks) | 250 | handle_t *ext4_journal_start_sb(struct super_block *sb, int nblocks) |
| 247 | { | 251 | { |
| 248 | journal_t *journal; | 252 | journal_t *journal; |
| 253 | handle_t *handle; | ||
| 249 | 254 | ||
| 250 | if (sb->s_flags & MS_RDONLY) | 255 | if (sb->s_flags & MS_RDONLY) |
| 251 | return ERR_PTR(-EROFS); | 256 | return ERR_PTR(-EROFS); |
| 252 | 257 | ||
| 253 | vfs_check_frozen(sb, SB_FREEZE_TRANS); | ||
| 254 | /* Special case here: if the journal has aborted behind our | ||
| 255 | * backs (eg. EIO in the commit thread), then we still need to | ||
| 256 | * take the FS itself readonly cleanly. */ | ||
| 257 | journal = EXT4_SB(sb)->s_journal; | 258 | journal = EXT4_SB(sb)->s_journal; |
| 258 | if (journal) { | 259 | handle = ext4_journal_current_handle(); |
