aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorAmir Goldstein <amir73il@gmail.com>2011-03-20 22:59:02 -0400
committerTheodore Ts'o <tytso@mit.edu>2011-03-20 22:59:02 -0400
commitd67d1218344009970ba0deb7eb15a3984518ddd0 (patch)
tree323e3fb76bdff2481fa35ce3aa82699434dae743 /fs
parent537a03103c67c4688b1e8e6671ad119aec5e2efb (diff)
ext4: handle errors in ext4_clear_blocks()
Checking return code from ext4_journal_get_write_access() is important with snapshots, because this function invokes COW, so may return new errors, such as ENOSPC. ext4_clear_blocks() now returns < 0 for fatal errors, in which case, ext4_free_data() is aborted. Signed-off-by: Amir Goldstein <amir73il@users.sf.net> Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Diffstat (limited to 'fs')
-rw-r--r--fs/ext4/inode.c46
1 files changed, 26 insertions, 20 deletions
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index 67e7a3caf9ed..fc8c0ce84315 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -4096,6 +4096,9 @@ no_top:
4096 * 4096 *
4097 * We release `count' blocks on disk, but (last - first) may be greater 4097 * We release `count' blocks on disk, but (last - first) may be greater
4098 * than `count' because there can be holes in there. 4098 * than `count' because there can be holes in there.
4099 *
4100 * Return 0 on success, 1 on invalid block range
4101 * and < 0 on fatal error.
4099 */ 4102 */
4100static int ext4_clear_blocks(handle_t *handle, struct inode *inode, 4103static int ext4_clear_blocks(handle_t *handle, struct inode *inode,
4101 struct buffer_head *bh, 4104 struct buffer_head *bh,
@@ -4122,25 +4125,21 @@ static int ext4_clear_blocks(handle_t *handle, struct inode *inode,
4122 if (bh) { 4125 if (bh) {
4123 BUFFER_TRACE(bh, "call ext4_handle_dirty_metadata"); 4126 BUFFER_TRACE(bh, "call ext4_handle_dirty_metadata");
4124 err = ext4_handle_dirty_metadata(handle, inode, bh); 4127 err = ext4_handle_dirty_metadata(handle, inode, bh);
4125 if (unlikely(err)) { 4128 if (unlikely(err))
4126 ext4_std_error(inode->i_sb, err); 4129 goto out_err;
4127 return 1;
4128 }
4129 } 4130 }
4130 err = ext4_mark_inode_dirty(handle, inode); 4131 err = ext4_mark_inode_dirty(handle, inode);
4131 if (unlikely(err)) { 4132 if (unlikely(err))
4132 ext4_std_error(inode->i_sb, err); 4133 goto out_err;
4133 return 1;
4134 }
4135 err = ext4_truncate_restart_trans(handle, inode, 4134 err = ext4_truncate_restart_trans(handle, inode,
4136 blocks_for_truncate(inode)); 4135 blocks_for_truncate(inode));
4137 if (unlikely(err)) { 4136 if (unlikely(err))
4138 ext4_std_error(inode->i_sb, err); 4137 goto out_err;
4139 return 1;
4140 }
4141 if (bh) { 4138 if (bh) {
4142 BUFFER_TRACE(bh, "retaking write access"); 4139 BUFFER_TRACE(bh, "retaking write access");
4143 ext4_journal_get_write_access(handle, bh); 4140 err = ext4_journal_get_write_access(handle, bh);
4141 if (unlikely(err))
4142 goto out_err;
4144 } 4143 }
4145 } 4144 }
4146 4145
@@ -4149,6 +4148,9 @@ static int ext4_clear_blocks(handle_t *handle, struct inode *inode,
4149 4148
4150 ext4_free_blocks(handle, inode, NULL, block_to_free, count, flags); 4149 ext4_free_blocks(handle, inode, NULL, block_to_free, count, flags);
4151 return 0; 4150 return 0;
4151out_err:
4152 ext4_std_error(inode->i_sb, err);
4153 return err;
4152} 4154}
4153 4155
4154/** 4156/**
@@ -4182,7 +4184,7 @@ static void ext4_free_data(handle_t *handle, struct inode *inode,
4182 ext4_fsblk_t nr; /* Current block # */ 4184 ext4_fsblk_t nr; /* Current block # */
4183 __le32 *p; /* Pointer into inode/ind 4185 __le32 *p; /* Pointer into inode/ind
4184 for current block */ 4186 for current block */
4185 int err; 4187 int err = 0;
4186 4188
4187 if (this_bh) { /* For indirect block */ 4189 if (this_bh) { /* For indirect block */
4188 BUFFER_TRACE(this_bh, "get_write_access"); 4190 BUFFER_TRACE(this_bh, "get_write_access");
@@ -4204,9 +4206,10 @@ static void ext4_free_data(handle_t *handle, struct inode *inode,
4204 } else if (nr == block_to_free + count) { 4206 } else if (nr == block_to_free + count) {
4205 count++; 4207 count++;
4206 } else { 4208 } else {
4207 if (ext4_clear_blocks(handle, inode, this_bh, 4209 err = ext4_clear_blocks(handle, inode, this_bh,
4208 block_to_free, count, 4210 block_to_free, count,
4209 block_to_free_p, p)) 4211 block_to_free_p, p);
4212 if (err)
4210 break; 4213 break;
4211 block_to_free = nr; 4214 block_to_free = nr;
4212 block_to_free_p = p; 4215 block_to_free_p = p;
@@ -4215,9 +4218,12 @@ static void ext4_free_data(handle_t *handle, struct inode *inode,
4215 } 4218 }
4216 } 4219 }
4217 4220
4218 if (count > 0) 4221 if (!err && count > 0)
4219 ext4_clear_blocks(handle, inode, this_bh, block_to_free, 4222 err = ext4_clear_blocks(handle, inode, this_bh, block_to_free,
4220 count, block_to_free_p, p); 4223 count, block_to_free_p, p);
4224 if (err < 0)
4225 /* fatal error */
4226 return;
4221 4227
4222 if (this_bh) { 4228 if (this_bh) {
4223 BUFFER_TRACE(this_bh, "call ext4_handle_dirty_metadata"); 4229 BUFFER_TRACE(this_bh, "call ext4_handle_dirty_metadata");