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 b49908a167a..acf1b142332 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; |
