aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ext4
diff options
context:
space:
mode:
authorTheodore Ts'o <tytso@mit.edu>2013-07-01 08:12:40 -0400
committerTheodore Ts'o <tytso@mit.edu>2013-07-01 08:12:40 -0400
commitcb530541182bee14112675046331f20a1c831507 (patch)
tree2a6f2d92aa5a956eea7e47331eb1ede78e81658f /fs/ext4
parent39c04153fda8c32e85b51c96eb5511a326ad7609 (diff)
ext4: fix up error handling for mpage_map_and_submit_extent()
The function mpage_released_unused_page() must only be called once; otherwise the kernel will BUG() when the second call to mpage_released_unused_page() tries to unlock the pages which had been unlocked by the first call. Also restructure the error handling so that we only give up on writing the dirty pages in the case of ENOSPC where retrying the allocation won't help. Otherwise, a transient failure, such as a kmalloc() failure in calling ext4_map_blocks() might cause us to give up on those pages, leading to a scary message in /var/log/messages plus data loss. Signed-off-by: "Theodore Ts'o" <tytso@mit.edu> Reviewed-by: Jan Kara <jack@suse.cz>
Diffstat (limited to 'fs/ext4')
-rw-r--r--fs/ext4/inode.c52
1 files changed, 28 insertions, 24 deletions
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index 502a9e1f5aa3..0188e65e1f58 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -2153,7 +2153,8 @@ static int mpage_map_one_extent(handle_t *handle, struct mpage_da_data *mpd)
2153 * guaranteed). After mapping we submit all mapped pages for IO. 2153 * guaranteed). After mapping we submit all mapped pages for IO.
2154 */ 2154 */
2155static int mpage_map_and_submit_extent(handle_t *handle, 2155static int mpage_map_and_submit_extent(handle_t *handle,
2156 struct mpage_da_data *mpd) 2156 struct mpage_da_data *mpd,
2157 bool *give_up_on_write)
2157{ 2158{
2158 struct inode *inode = mpd->inode; 2159 struct inode *inode = mpd->inode;
2159 struct ext4_map_blocks *map = &mpd->map; 2160 struct ext4_map_blocks *map = &mpd->map;
@@ -2167,29 +2168,30 @@ static int mpage_map_and_submit_extent(handle_t *handle,
2167 if (err < 0) { 2168 if (err < 0) {
2168 struct super_block *sb = inode->i_sb; 2169 struct super_block *sb = inode->i_sb;
2169 2170
2171 if (EXT4_SB(sb)->s_mount_flags & EXT4_MF_FS_ABORTED)
2172 goto invalidate_dirty_pages;
2170 /* 2173 /*
2171 * Need to commit transaction to free blocks. Let upper 2174 * Let the uper layers retry transient errors.
2172 * layers sort it out. 2175 * In the case of ENOSPC, if ext4_count_free_blocks()
2176 * is non-zero, a commit should free up blocks.
2173 */ 2177 */
2174 if (err == -ENOSPC && ext4_count_free_clusters(sb)) 2178 if ((err == -ENOMEM) ||
2175 return -ENOSPC; 2179 (err == -ENOSPC && ext4_count_free_clusters(sb)))
2176 2180 return err;
2177 if (!(EXT4_SB(sb)->s_mount_flags & EXT4_MF_FS_ABORTED)) { 2181 ext4_msg(sb, KERN_CRIT,
2178 ext4_msg(sb, KERN_CRIT, 2182 "Delayed block allocation failed for "
2179 "Delayed block allocation failed for " 2183 "inode %lu at logical offset %llu with"
2180 "inode %lu at logical offset %llu with" 2184 " max blocks %u with error %d",
2181 " max blocks %u with error %d", 2185 inode->i_ino,
2182 inode->i_ino, 2186 (unsigned long long)map->m_lblk,
2183 (unsigned long long)map->m_lblk, 2187 (unsigned)map->m_len, -err);
2184 (unsigned)map->m_len, err); 2188 ext4_msg(sb, KERN_CRIT,
2185 ext4_msg(sb, KERN_CRIT, 2189 "This should not happen!! Data will "
2186 "This should not happen!! Data will " 2190 "be lost\n");
2187 "be lost\n"); 2191 if (err == -ENOSPC)
2188 if (err == -ENOSPC) 2192 ext4_print_free_blocks(inode);
2189 ext4_print_free_blocks(inode); 2193 invalidate_dirty_pages:
2190 } 2194 *give_up_on_write = true;
2191 /* invalidate all the pages */
2192 mpage_release_unused_pages(mpd, true);
2193 return err; 2195 return err;
2194 } 2196 }
2195 /* 2197 /*
@@ -2377,6 +2379,7 @@ static int ext4_writepages(struct address_space *mapping,
2377 struct ext4_sb_info *sbi = EXT4_SB(mapping->host->i_sb); 2379 struct ext4_sb_info *sbi = EXT4_SB(mapping->host->i_sb);
2378 bool done; 2380 bool done;
2379 struct blk_plug plug; 2381 struct blk_plug plug;
2382 bool give_up_on_write = false;
2380 2383
2381 trace_ext4_writepages(inode, wbc); 2384 trace_ext4_writepages(inode, wbc);
2382 2385
@@ -2494,7 +2497,8 @@ retry:
2494 ret = mpage_prepare_extent_to_map(&mpd); 2497 ret = mpage_prepare_extent_to_map(&mpd);
2495 if (!ret) { 2498 if (!ret) {
2496 if (mpd.map.m_len) 2499 if (mpd.map.m_len)
2497 ret = mpage_map_and_submit_extent(handle, &mpd); 2500 ret = mpage_map_and_submit_extent(handle, &mpd,
2501 &give_up_on_write);
2498 else { 2502 else {
2499 /* 2503 /*
2500 * We scanned the whole range (or exhausted 2504 * We scanned the whole range (or exhausted
@@ -2509,7 +2513,7 @@ retry:
2509 /* Submit prepared bio */ 2513 /* Submit prepared bio */
2510 ext4_io_submit(&mpd.io_submit); 2514 ext4_io_submit(&mpd.io_submit);
2511 /* Unlock pages we didn't use */ 2515 /* Unlock pages we didn't use */
2512 mpage_release_unused_pages(&mpd, false); 2516 mpage_release_unused_pages(&mpd, give_up_on_write);
2513 /* Drop our io_end reference we got from init */ 2517 /* Drop our io_end reference we got from init */
2514 ext4_put_io_end(mpd.io_submit.io_end); 2518 ext4_put_io_end(mpd.io_submit.io_end);
2515 2519