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 953b430f92e3..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 | /* |
@@ -2075,7 +2086,7 @@ static void ext3_clear_blocks(handle_t *handle, struct inode *inode, | |||
2075 | ext3_journal_dirty_metadata(handle, bh); | 2086 | ext3_journal_dirty_metadata(handle, bh); |
2076 | } | 2087 | } |
2077 | ext3_mark_inode_dirty(handle, inode); | 2088 | ext3_mark_inode_dirty(handle, inode); |
2078 | ext3_journal_test_restart(handle, inode); | 2089 | truncate_restart_transaction(handle, inode); |
2079 | if (bh) { | 2090 | if (bh) { |
2080 | BUFFER_TRACE(bh, "retaking write access"); | 2091 | BUFFER_TRACE(bh, "retaking write access"); |
2081 | ext3_journal_get_write_access(handle, bh); | 2092 | ext3_journal_get_write_access(handle, bh); |
@@ -2285,7 +2296,7 @@ static void ext3_free_branches(handle_t *handle, struct inode *inode, | |||
2285 | return; | 2296 | return; |
2286 | if (try_to_extend_transaction(handle, inode)) { | 2297 | if (try_to_extend_transaction(handle, inode)) { |
2287 | ext3_mark_inode_dirty(handle, inode); | 2298 | ext3_mark_inode_dirty(handle, inode); |
2288 | ext3_journal_test_restart(handle, inode); | 2299 | truncate_restart_transaction(handle, inode); |
2289 | } | 2300 | } |
2290 | 2301 | ||
2291 | ext3_free_blocks(handle, inode, nr, 1); | 2302 | ext3_free_blocks(handle, inode, nr, 1); |
@@ -2895,6 +2906,10 @@ static int ext3_do_update_inode(handle_t *handle, | |||
2895 | struct buffer_head *bh = iloc->bh; | 2906 | struct buffer_head *bh = iloc->bh; |
2896 | int err = 0, rc, block; | 2907 | int err = 0, rc, block; |
2897 | 2908 | ||
2909 | again: | ||
2910 | /* we can't allow multiple procs in here at once, its a bit racey */ | ||
2911 | lock_buffer(bh); | ||
2912 | |||
2898 | /* For fields not not tracking in the in-memory inode, | 2913 | /* For fields not not tracking in the in-memory inode, |
2899 | * initialise them to zero for new inodes. */ | 2914 | * initialise them to zero for new inodes. */ |
2900 | if (ei->i_state & EXT3_STATE_NEW) | 2915 | if (ei->i_state & EXT3_STATE_NEW) |
@@ -2954,16 +2969,20 @@ static int ext3_do_update_inode(handle_t *handle, | |||
2954 | /* If this is the first large file | 2969 | /* If this is the first large file |
2955 | * created, add a flag to the superblock. | 2970 | * created, add a flag to the superblock. |
2956 | */ | 2971 | */ |
2972 | unlock_buffer(bh); | ||
2957 | err = ext3_journal_get_write_access(handle, | 2973 | err = ext3_journal_get_write_access(handle, |
2958 | EXT3_SB(sb)->s_sbh); | 2974 | EXT3_SB(sb)->s_sbh); |
2959 | if (err) | 2975 | if (err) |
2960 | goto out_brelse; | 2976 | goto out_brelse; |
2977 | |||
2961 | ext3_update_dynamic_rev(sb); | 2978 | ext3_update_dynamic_rev(sb); |
2962 | EXT3_SET_RO_COMPAT_FEATURE(sb, | 2979 | EXT3_SET_RO_COMPAT_FEATURE(sb, |
2963 | EXT3_FEATURE_RO_COMPAT_LARGE_FILE); | 2980 | EXT3_FEATURE_RO_COMPAT_LARGE_FILE); |
2964 | handle->h_sync = 1; | 2981 | handle->h_sync = 1; |
2965 | err = ext3_journal_dirty_metadata(handle, | 2982 | err = ext3_journal_dirty_metadata(handle, |
2966 | EXT3_SB(sb)->s_sbh); | 2983 | EXT3_SB(sb)->s_sbh); |
2984 | /* get our lock and start over */ | ||
2985 | goto again; | ||
2967 | } | 2986 | } |
2968 | } | 2987 | } |
2969 | } | 2988 | } |
@@ -2986,6 +3005,7 @@ static int ext3_do_update_inode(handle_t *handle, | |||
2986 | 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); |
2987 | 3006 | ||
2988 | BUFFER_TRACE(bh, "call ext3_journal_dirty_metadata"); | 3007 | BUFFER_TRACE(bh, "call ext3_journal_dirty_metadata"); |
3008 | unlock_buffer(bh); | ||
2989 | rc = ext3_journal_dirty_metadata(handle, bh); | 3009 | rc = ext3_journal_dirty_metadata(handle, bh); |
2990 | if (!err) | 3010 | if (!err) |
2991 | err = rc; | 3011 | err = rc; |