diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-08-29 14:52:46 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-08-29 14:52:46 -0400 |
| commit | d4f03186c8986ffde34d06fe74a99aab08f7ee0b (patch) | |
| tree | 9887bc2405a4f9e17185aa1338dec3ae68246b16 | |
| parent | ef13c8afa67518e1d173a6f3b95dd02559879421 (diff) | |
| parent | d80d448c6c5bdd32605b78a60fe8081d82d4da0f (diff) | |
Merge tag 'ext4_for_linus_stable' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4
Pull ext4 bugfixes from Ted Ts'o:
"Ext4 bug fixes for 3.17, to provide better handling of memory
allocation failures, and to fix some journaling bugs involving
journal checksums and FALLOC_FL_ZERO_RANGE"
* tag 'ext4_for_linus_stable' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4:
ext4: fix same-dir rename when inline data directory overflows
jbd2: fix descriptor block size handling errors with journal_csum
jbd2: fix infinite loop when recovering corrupt journal blocks
ext4: update i_disksize coherently with block allocation on error path
ext4: fix transaction issues for ext4_fallocate and ext_zero_range
ext4: fix incorect journal credits reservation in ext4_zero_range
ext4: move i_size,i_disksize update routines to helper function
ext4: fix BUG_ON in mb_free_blocks()
ext4: propagate errors up to ext4_find_entry()'s callers
| -rw-r--r-- | fs/ext4/ext4.h | 18 | ||||
| -rw-r--r-- | fs/ext4/extents.c | 88 | ||||
| -rw-r--r-- | fs/ext4/inode.c | 44 | ||||
| -rw-r--r-- | fs/ext4/mballoc.c | 5 | ||||
| -rw-r--r-- | fs/ext4/namei.c | 56 | ||||
| -rw-r--r-- | fs/ext4/super.c | 5 | ||||
| -rw-r--r-- | fs/jbd2/commit.c | 21 | ||||
| -rw-r--r-- | fs/jbd2/journal.c | 56 | ||||
| -rw-r--r-- | fs/jbd2/recovery.c | 33 | ||||
| -rw-r--r-- | fs/jbd2/revoke.c | 6 | ||||
| -rw-r--r-- | include/linux/jbd2.h | 30 |
11 files changed, 233 insertions, 129 deletions
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index 5b19760b1de5..b0c225cdb52c 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h | |||
| @@ -1825,7 +1825,7 @@ ext4_group_first_block_no(struct super_block *sb, ext4_group_t group_no) | |||
| 1825 | /* | 1825 | /* |
| 1826 | * Special error return code only used by dx_probe() and its callers. | 1826 | * Special error return code only used by dx_probe() and its callers. |
| 1827 | */ | 1827 | */ |
| 1828 | #define ERR_BAD_DX_DIR -75000 | 1828 | #define ERR_BAD_DX_DIR (-(MAX_ERRNO - 1)) |
| 1829 | 1829 | ||
| 1830 | /* | 1830 | /* |
| 1831 | * Timeout and state flag for lazy initialization inode thread. | 1831 | * Timeout and state flag for lazy initialization inode thread. |
| @@ -2454,6 +2454,22 @@ static inline void ext4_update_i_disksize(struct inode *inode, loff_t newsize) | |||
| 2454 | up_write(&EXT4_I(inode)->i_data_sem); | 2454 | up_write(&EXT4_I(inode)->i_data_sem); |
| 2455 | } | 2455 | } |
| 2456 | 2456 | ||
| 2457 | /* Update i_size, i_disksize. Requires i_mutex to avoid races with truncate */ | ||
| 2458 | static inline int ext4_update_inode_size(struct inode *inode, loff_t newsize) | ||
| 2459 | { | ||
| 2460 | int changed = 0; | ||
| 2461 | |||
| 2462 | if (newsize > inode->i_size) { | ||
| 2463 | i_size_write(inode, newsize); | ||
| 2464 | changed = 1; | ||
| 2465 | } | ||
| 2466 | if (newsize > EXT4_I(inode)->i_disksize) { | ||
| 2467 | ext4_update_i_disksize(inode, newsize); | ||
| 2468 | changed |= 2; | ||
| 2469 | } | ||
| 2470 | return changed; | ||
| 2471 | } | ||
| 2472 | |||
| 2457 | struct ext4_group_info { | 2473 | struct ext4_group_info { |
| 2458 | unsigned long bb_state; | 2474 | unsigned long bb_state; |
| 2459 | struct rb_root bb_free_root; | 2475 | struct rb_root bb_free_root; |
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 76c2df382b7d..74292a71b384 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c | |||
| @@ -4665,7 +4665,8 @@ retry: | |||
| 4665 | } | 4665 | } |
| 4666 | 4666 | ||
| 4667 | static int ext4_alloc_file_blocks(struct file *file, ext4_lblk_t offset, | 4667 | static int ext4_alloc_file_blocks(struct file *file, ext4_lblk_t offset, |
| 4668 | ext4_lblk_t len, int flags, int mode) | 4668 | ext4_lblk_t len, loff_t new_size, |
| 4669 | int flags, int mode) | ||
| 4669 | { | 4670 | { |
| 4670 | struct inode *inode = file_inode(file); | 4671 | struct inode *inode = file_inode(file); |
| 4671 | handle_t *handle; | 4672 | handle_t *handle; |
| @@ -4674,8 +4675,10 @@ static int ext4_alloc_file_blocks(struct file *file, ext4_lblk_t offset, | |||
| 4674 | int retries = 0; | 4675 | int retries = 0; |
| 4675 | struct ext4_map_blocks map; | 4676 | struct ext4_map_blocks map; |
| 4676 | unsigned int credits; | 4677 | unsigned int credits; |
| 4678 | loff_t epos; | ||
| 4677 | 4679 | ||
| 4678 | map.m_lblk = offset; | 4680 | map.m_lblk = offset; |
| 4681 | map.m_len = len; | ||
| 4679 | /* | 4682 | /* |
| 4680 | * Don't normalize the request if it can fit in one extent so | 4683 | * Don't normalize the request if it can fit in one extent so |
| 4681 | * that it doesn't get unnecessarily split into multiple | 4684 | * that it doesn't get unnecessarily split into multiple |
| @@ -4690,9 +4693,7 @@ static int ext4_alloc_file_blocks(struct file *file, ext4_lblk_t offset, | |||
| 4690 | credits = ext4_chunk_trans_blocks(inode, len); | 4693 | credits = ext4_chunk_trans_blocks(inode, len); |
| 4691 | 4694 | ||
| 4692 | retry: | 4695 | retry: |
| 4693 | while (ret >= 0 && ret < len) { | 4696 | while (ret >= 0 && len) { |
| 4694 | map.m_lblk = map.m_lblk + ret; | ||
| 4695 | map.m_len = len = len - ret; | ||
| 4696 | handle = ext4_journal_start(inode, EXT4_HT_MAP_BLOCKS, | 4697 | handle = ext4_journal_start(inode, EXT4_HT_MAP_BLOCKS, |
| 4697 | credits); | 4698 | credits); |
| 4698 | if (IS_ERR(handle)) { | 4699 | if (IS_ERR(handle)) { |
| @@ -4709,6 +4710,21 @@ retry: | |||
| 4709 | ret2 = ext4_journal_stop(handle); | 4710 | ret2 = ext4_journal_stop(handle); |
| 4710 | break; | 4711 | break; |
| 4711 | } | 4712 | } |
| 4713 | map.m_lblk += ret; | ||
| 4714 | map.m_len = len = len - ret; | ||
| 4715 | epos = (loff_t)map.m_lblk << inode->i_blkbits; | ||
| 4716 | inode->i_ctime = ext4_current_time(inode); | ||
| 4717 | if (new_size) { | ||
| 4718 | if (epos > new_size) | ||
| 4719 | epos = new_size; | ||
| 4720 | if (ext4_update_inode_size(inode, epos) & 0x1) | ||
| 4721 | inode->i_mtime = inode->i_ctime; | ||
| 4722 | } else { | ||
| 4723 | if (epos > inode->i_size) | ||
| 4724 | ext4_set_inode_flag(inode, | ||
| 4725 | EXT4_INODE_EOFBLOCKS); | ||
| 4726 | } | ||
| 4727 | ext4_mark_inode_dirty(handle, inode); | ||
| 4712 | ret2 = ext4_journal_stop(handle); | 4728 | ret2 = ext4_journal_stop(handle); |
| 4713 | if (ret2) | 4729 | if (ret2) |
| 4714 | break; | 4730 | break; |
| @@ -4731,7 +4747,8 @@ static long ext4_zero_range(struct file *file, loff_t offset, | |||
| 4731 | loff_t new_size = 0; | 4747 | loff_t new_size = 0; |
| 4732 | int ret = 0; | 4748 | int ret = 0; |
| 4733 | int flags; | 4749 | int flags; |
| 4734 | int partial; | 4750 | int credits; |
| 4751 | int partial_begin, partial_end; | ||
| 4735 | loff_t start, end; | 4752 | loff_t start, end; |
| 4736 | ext4_lblk_t lblk; | 4753 | ext4_lblk_t lblk; |
| 4737 | struct address_space *mapping = inode->i_mapping; | 4754 | struct address_space *mapping = inode->i_mapping; |
| @@ -4771,7 +4788,8 @@ static long ext4_zero_range(struct file *file, loff_t offset, | |||
| 4771 | 4788 | ||
| 4772 | if (start < offset || end > offset + len) | 4789 | if (start < offset || end > offset + len) |
| 4773 | return -EINVAL; | 4790 | return -EINVAL; |
| 4774 | partial = (offset + len) & ((1 << blkbits) - 1); | 4791 | partial_begin = offset & ((1 << blkbits) - 1); |
| 4792 | partial_end = (offset + len) & ((1 << blkbits) - 1); | ||
| 4775 | 4793 | ||
| 4776 | lblk = start >> blkbits; | 4794 | lblk = start >> blkbits; |
| 4777 | max_blocks = (end >> blkbits); | 4795 | max_blocks = (end >> blkbits); |
| @@ -4805,7 +4823,7 @@ static long ext4_zero_range(struct file *file, loff_t offset, | |||
| 4805 | * If we have a partial block after EOF we have to allocate | 4823 | * If we have a partial block after EOF we have to allocate |
| 4806 | * the entire block. | 4824 | * the entire block. |
| 4807 | */ | 4825 | */ |
| 4808 | if (partial) | 4826 | if (partial_end) |
| 4809 | max_blocks += 1; | 4827 | max_blocks += 1; |
| 4810 | } | 4828 | } |
| 4811 | 4829 | ||
| @@ -4813,6 +4831,7 @@ static long ext4_zero_range(struct file *file, loff_t offset, | |||
| 4813 | 4831 | ||
| 4814 | /* Now release the pages and zero block aligned part of pages*/ | 4832 | /* Now release the pages and zero block aligned part of pages*/ |
| 4815 | truncate_pagecache_range(inode, start, end - 1); | 4833 | truncate_pagecache_range(inode, start, end - 1); |
| 4834 | inode->i_mtime = inode->i_ctime = ext4_current_time(inode); | ||
| 4816 | 4835 | ||
| 4817 | /* Wait all existing dio workers, newcomers will block on i_mutex */ | 4836 | /* Wait all existing dio workers, newcomers will block on i_mutex */ |
| 4818 | ext4_inode_block_unlocked_dio(inode); | 4837 | ext4_inode_block_unlocked_dio(inode); |
| @@ -4825,13 +4844,22 @@ static long ext4_zero_range(struct file *file, loff_t offset, | |||
| 4825 | if (ret) | 4844 | if (ret) |
| 4826 | goto out_dio; | 4845 | goto out_dio; |
| 4827 | 4846 | ||
| 4828 | ret = ext4_alloc_file_blocks(file, lblk, max_blocks, flags, | 4847 | ret = ext4_alloc_file_blocks(file, lblk, max_blocks, new_size, |
| 4829 | mode); | 4848 | flags, mode); |
| 4830 | if (ret) | 4849 | if (ret) |
| 4831 | goto out_dio; | 4850 | goto out_dio; |
| 4832 | } | 4851 | } |
| 4852 | if (!partial_begin && !partial_end) | ||
| 4853 | goto out_dio; | ||
| 4833 | 4854 | ||
| 4834 | handle = ext4_journal_start(inode, EXT4_HT_MISC, 4); | 4855 | /* |
| 4856 | * In worst case we have to writeout two nonadjacent unwritten | ||
| 4857 | * blocks and update the inode | ||
| 4858 | */ | ||
| 4859 | credits = (2 * ext4_ext_index_trans_blocks(inode, 2)) + 1; | ||
| 4860 | if (ext4_should_journal_data(inode)) | ||
| 4861 | credits += 2; | ||
| 4862 | handle = ext4_journal_start(inode, EXT4_HT_MISC, credits); | ||
| 4835 | if (IS_ERR(handle)) { | 4863 | if (IS_ERR(handle)) { |
| 4836 | ret = PTR_ERR(handle); | 4864 | ret = PTR_ERR(handle); |
