diff options
Diffstat (limited to 'fs/ext3/inode.c')
-rw-r--r-- | fs/ext3/inode.c | 28 |
1 files changed, 24 insertions, 4 deletions
diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c index b49908a167ae..cd098a7b77fc 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); |
@@ -2892,6 +2903,10 @@ static int ext3_do_update_inode(handle_t *handle, | |||
2892 | struct buffer_head *bh = iloc->bh; | 2903 | struct buffer_head *bh = iloc->bh; |
2893 | int err = 0, rc, block; | 2904 | int err = 0, rc, block; |
2894 | 2905 | ||
2906 | again: | ||
2907 | /* we can't allow multiple procs in here at once, its a bit racey */ | ||
2908 | lock_buffer(bh); | ||
2909 | |||
2895 | /* For fields not not tracking in the in-memory inode, | 2910 | /* For fields not not tracking in the in-memory inode, |
2896 | * initialise them to zero for new inodes. */ | 2911 | * initialise them to zero for new inodes. */ |
2897 | if (ei->i_state & EXT3_STATE_NEW) | 2912 | if (ei->i_state & EXT3_STATE_NEW) |
@@ -2951,16 +2966,20 @@ static int ext3_do_update_inode(handle_t *handle, | |||
2951 | /* If this is the first large file | 2966 | /* If this is the first large file |
2952 | * created, add a flag to the superblock. | 2967 | * created, add a flag to the superblock. |
2953 | */ | 2968 | */ |
2969 | unlock_buffer(bh); | ||
2954 | err = ext3_journal_get_write_access(handle, | 2970 | err = ext3_journal_get_write_access(handle, |
2955 | EXT3_SB(sb)->s_sbh); | 2971 | EXT3_SB(sb)->s_sbh); |
2956 | if (err) | 2972 | if (err) |
2957 | goto out_brelse; | 2973 | goto out_brelse; |
2974 | |||
2958 | ext3_update_dynamic_rev(sb); | 2975 | ext3_update_dynamic_rev(sb); |
2959 | EXT3_SET_RO_COMPAT_FEATURE(sb, | 2976 | EXT3_SET_RO_COMPAT_FEATURE(sb, |
2960 | EXT3_FEATURE_RO_COMPAT_LARGE_FILE); | 2977 | EXT3_FEATURE_RO_COMPAT_LARGE_FILE); |
2961 | handle->h_sync = 1; | 2978 | handle->h_sync = 1; |
2962 | err = ext3_journal_dirty_metadata(handle, | 2979 | err = ext3_journal_dirty_metadata(handle, |
2963 | EXT3_SB(sb)->s_sbh); | 2980 | EXT3_SB(sb)->s_sbh); |
2981 | /* get our lock and start over */ | ||
2982 | goto again; | ||
2964 | } | 2983 | } |
2965 | } | 2984 | } |
2966 | } | 2985 | } |
@@ -2983,6 +3002,7 @@ static int ext3_do_update_inode(handle_t *handle, | |||
2983 | raw_inode->i_extra_isize = cpu_to_le16(ei->i_extra_isize); | 3002 | raw_inode->i_extra_isize = cpu_to_le16(ei->i_extra_isize); |
2984 | 3003 | ||
2985 | BUFFER_TRACE(bh, "call ext3_journal_dirty_metadata"); | 3004 | BUFFER_TRACE(bh, "call ext3_journal_dirty_metadata"); |
3005 | unlock_buffer(bh); | ||
2986 | rc = ext3_journal_dirty_metadata(handle, bh); | 3006 | rc = ext3_journal_dirty_metadata(handle, bh); |
2987 | if (!err) | 3007 | if (!err) |
2988 | err = rc; | 3008 | err = rc; |