diff options
Diffstat (limited to 'fs/ext3/inode.c')
-rw-r--r-- | fs/ext3/inode.c | 19 |
1 files changed, 15 insertions, 4 deletions
diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c index b49908a167ae..eb0b4e0d517b 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 | /* |
@@ -2072,7 +2083,7 @@ static void ext3_clear_blocks(handle_t *handle, struct inode *inode, | |||
2072 | ext3_journal_dirty_metadata(handle, bh); | 2083 | ext3_journal_dirty_metadata(handle, bh); |
2073 | } | 2084 | } |
2074 | ext3_mark_inode_dirty(handle, inode); | 2085 | ext3_mark_inode_dirty(handle, inode); |
2075 | ext3_journal_test_restart(handle, inode); | 2086 | truncate_restart_transaction(handle, inode); |
2076 | if (bh) { | 2087 | if (bh) { |
2077 | BUFFER_TRACE(bh, "retaking write access"); | 2088 | BUFFER_TRACE(bh, "retaking write access"); |
2078 | ext3_journal_get_write_access(handle, bh); | 2089 | ext3_journal_get_write_access(handle, bh); |
@@ -2282,7 +2293,7 @@ static void ext3_free_branches(handle_t *handle, struct inode *inode, | |||
2282 | return; | 2293 | return; |
2283 | if (try_to_extend_transaction(handle, inode)) { | 2294 | if (try_to_extend_transaction(handle, inode)) { |
2284 | ext3_mark_inode_dirty(handle, inode); | 2295 | ext3_mark_inode_dirty(handle, inode); |
2285 | ext3_journal_test_restart(handle, inode); | 2296 | truncate_restart_transaction(handle, inode); |
2286 | } | 2297 | } |
2287 | 2298 | ||
2288 | ext3_free_blocks(handle, inode, nr, 1); | 2299 | ext3_free_blocks(handle, inode, nr, 1); |