diff options
Diffstat (limited to 'fs/ext3/inode.c')
-rw-r--r-- | fs/ext3/inode.c | 31 |
1 files changed, 27 insertions, 4 deletions
diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c index b49908a167ae..acf1b1423327 100644 --- a/fs/ext3/inode.c +++ b/fs/ext3/inode.c | |||
@@ -172,10 +172,21 @@ static int try_to_extend_transaction(handle_t *handle, struct inode *inode) | |||
172 | * so before we call here everything must be consistently dirtied against | 172 | * so before we call here everything must be consistently dirtied against |
173 | * this transaction. | 173 | * this transaction. |
174 | */ | 174 | */ |
175 | static int ext3_journal_test_restart(handle_t *handle, struct inode *inode) | 175 | static int truncate_restart_transaction(handle_t *handle, struct inode *inode) |
176 | { | 176 | { |
177 | int ret; | ||
178 | |||
177 | jbd_debug(2, "restarting handle %p\n", handle); | 179 | jbd_debug(2, "restarting handle %p\n", handle); |
178 | return ext3_journal_restart(handle, blocks_for_truncate(inode)); | 180 | /* |
181 | * Drop truncate_mutex to avoid deadlock with ext3_get_blocks_handle | ||
182 | * At this moment, get_block can be called only for blocks inside | ||
183 | * i_size since page cache has been already dropped and writes are | ||
184 | * blocked by i_mutex. So we can safely drop the truncate_mutex. | ||
185 | */ | ||
186 | mutex_unlock(&EXT3_I(inode)->truncate_mutex); | ||
187 | ret = ext3_journal_restart(handle, blocks_for_truncate(inode)); | ||
188 | mutex_lock(&EXT3_I(inode)->truncate_mutex); | ||
189 | return ret; | ||
179 | } | 190 | } |
180 | 191 | ||
181 | /* | 192 | /* |
@@ -1819,6 +1830,7 @@ static const struct address_space_operations ext3_ordered_aops = { | |||
1819 | .direct_IO = ext3_direct_IO, | 1830 | .direct_IO = ext3_direct_IO, |
1820 | .migratepage = buffer_migrate_page, | 1831 | .migratepage = buffer_migrate_page, |
1821 | .is_partially_uptodate = block_is_partially_uptodate, | 1832 | .is_partially_uptodate = block_is_partially_uptodate, |
1833 | .error_remove_page = generic_error_remove_page, | ||
1822 | }; | 1834 | }; |
1823 | 1835 | ||
1824 | static const struct address_space_operations ext3_writeback_aops = { | 1836 | static const struct address_space_operations ext3_writeback_aops = { |
@@ -1834,6 +1846,7 @@ static const struct address_space_operations ext3_writeback_aops = { | |||
1834 | .direct_IO = ext3_direct_IO, | 1846 | .direct_IO = ext3_direct_IO, |
1835 | .migratepage = buffer_migrate_page, | 1847 | .migratepage = buffer_migrate_page, |
1836 | .is_partially_uptodate = block_is_partially_uptodate, | 1848 | .is_partially_uptodate = block_is_partially_uptodate, |
1849 | .error_remove_page = generic_error_remove_page, | ||
1837 | }; | 1850 | }; |
1838 | 1851 | ||
1839 | static const struct address_space_operations ext3_journalled_aops = { | 1852 | static const struct address_space_operations ext3_journalled_aops = { |
@@ -1848,6 +1861,7 @@ static const struct address_space_operations ext3_journalled_aops = { | |||
1848 | .invalidatepage = ext3_invalidatepage, | 1861 | .invalidatepage = ext3_invalidatepage, |
1849 | .releasepage = ext3_releasepage, | 1862 | .releasepage = ext3_releasepage, |
1850 | .is_partially_uptodate = block_is_partially_uptodate, | 1863 | .is_partially_uptodate = block_is_partially_uptodate, |
1864 | .error_remove_page = generic_error_remove_page, | ||
1851 | }; | 1865 | }; |
1852 | 1866 | ||
1853 | void ext3_set_aops(struct inode *inode) | 1867 | void ext3_set_aops(struct inode *inode) |
@@ -2072,7 +2086,7 @@ static void ext3_clear_blocks(handle_t *handle, struct inode *inode, | |||
2072 | ext3_journal_dirty_metadata(handle, bh); | 2086 | ext3_journal_dirty_metadata(handle, bh); |
2073 | } | 2087 | } |
2074 | ext3_mark_inode_dirty(handle, inode); | 2088 | ext3_mark_inode_dirty(handle, inode); |
2075 | ext3_journal_test_restart(handle, inode); | 2089 | truncate_restart_transaction(handle, inode); |
2076 | if (bh) { | 2090 | if (bh) { |
2077 | BUFFER_TRACE(bh, "retaking write access"); | 2091 | BUFFER_TRACE(bh, "retaking write access"); |
2078 | ext3_journal_get_write_access(handle, bh); | 2092 | ext3_journal_get_write_access(handle, bh); |
@@ -2282,7 +2296,7 @@ static void ext3_free_branches(handle_t *handle, struct inode *inode, | |||
2282 | return; | 2296 | return; |
2283 | if (try_to_extend_transaction(handle, inode)) { | 2297 | if (try_to_extend_transaction(handle, inode)) { |
2284 | ext3_mark_inode_dirty(handle, inode); | 2298 | ext3_mark_inode_dirty(handle, inode); |
2285 | ext3_journal_test_restart(handle, inode); | 2299 | truncate_restart_transaction(handle, inode); |
2286 | } | 2300 | } |
2287 | 2301 | ||
2288 | ext3_free_blocks(handle, inode, nr, 1); | 2302 | ext3_free_blocks(handle, inode, nr, 1); |
@@ -2892,6 +2906,10 @@ static int ext3_do_update_inode(handle_t *handle, | |||
2892 | struct buffer_head *bh = iloc->bh; | 2906 | struct buffer_head *bh = iloc->bh; |
2893 | int err = 0, rc, block; | 2907 | int err = 0, rc, block; |
2894 | 2908 | ||
2909 | again: | ||
2910 | /* we can't allow multiple procs in here at once, its a bit racey */ | ||
2911 | lock_buffer(bh); | ||
2912 | |||
2895 | /* For fields not not tracking in the in-memory inode, | 2913 | /* For fields not not tracking in the in-memory inode, |
2896 | * initialise them to zero for new inodes. */ | 2914 | * initialise them to zero for new inodes. */ |
2897 | if (ei->i_state & EXT3_STATE_NEW) | 2915 | if (ei->i_state & EXT3_STATE_NEW) |
@@ -2951,16 +2969,20 @@ static int ext3_do_update_inode(handle_t *handle, | |||
2951 | /* If this is the first large file | 2969 | /* If this is the first large file |
2952 | * created, add a flag to the superblock. | 2970 | * created, add a flag to the superblock. |
2953 | */ | 2971 | */ |
2972 | unlock_buffer(bh); | ||
2954 | err = ext3_journal_get_write_access(handle, | 2973 | err = ext3_journal_get_write_access(handle, |
2955 | EXT3_SB(sb)->s_sbh); | 2974 | EXT3_SB(sb)->s_sbh); |
2956 | if (err) | 2975 | if (err) |
2957 | goto out_brelse; | 2976 | goto out_brelse; |
2977 | |||
2958 | ext3_update_dynamic_rev(sb); | 2978 | ext3_update_dynamic_rev(sb); |
2959 | EXT3_SET_RO_COMPAT_FEATURE(sb, | 2979 | EXT3_SET_RO_COMPAT_FEATURE(sb, |
2960 | EXT3_FEATURE_RO_COMPAT_LARGE_FILE); | 2980 | EXT3_FEATURE_RO_COMPAT_LARGE_FILE); |
2961 | handle->h_sync = 1; | 2981 | handle->h_sync = 1; |
2962 | err = ext3_journal_dirty_metadata(handle, | 2982 | err = ext3_journal_dirty_metadata(handle, |
2963 | EXT3_SB(sb)->s_sbh); | 2983 | EXT3_SB(sb)->s_sbh); |
2984 | /* get our lock and start over */ | ||
2985 | goto again; | ||
2964 | } | 2986 | } |
2965 | } | 2987 | } |
2966 | } | 2988 | } |
@@ -2983,6 +3005,7 @@ static int ext3_do_update_inode(handle_t *handle, | |||
2983 | raw_inode->i_extra_isize = cpu_to_le16(ei->i_extra_isize); | 3005 | raw_inode->i_extra_isize = cpu_to_le16(ei->i_extra_isize); |
2984 | 3006 | ||
2985 | BUFFER_TRACE(bh, "call ext3_journal_dirty_metadata"); | 3007 | BUFFER_TRACE(bh, "call ext3_journal_dirty_metadata"); |
3008 | unlock_buffer(bh); | ||
2986 | rc = ext3_journal_dirty_metadata(handle, bh); | 3009 | rc = ext3_journal_dirty_metadata(handle, bh); |
2987 | if (!err) | 3010 | if (!err) |
2988 | err = rc; | 3011 | err = rc; |