aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/ext4/ext4.h1
-rw-r--r--fs/ext4/inode.c39
-rw-r--r--fs/ext4/mballoc.c7
3 files changed, 35 insertions, 12 deletions
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index 602d5ad6f5e7..307ecd13a762 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -377,6 +377,7 @@ struct ext4_new_group_data {
377 */ 377 */
378#define EXT4_FREE_BLOCKS_METADATA 0x0001 378#define EXT4_FREE_BLOCKS_METADATA 0x0001
379#define EXT4_FREE_BLOCKS_FORGET 0x0002 379#define EXT4_FREE_BLOCKS_FORGET 0x0002
380#define EXT4_FREE_BLOCKS_VALIDATED 0x0004
380 381
381/* 382/*
382 * ioctl commands 383 * ioctl commands
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index 2059c34ac4c8..3e8afd969236 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -4130,18 +4130,27 @@ no_top:
4130 * We release `count' blocks on disk, but (last - first) may be greater 4130 * We release `count' blocks on disk, but (last - first) may be greater
4131 * than `count' because there can be holes in there. 4131 * than `count' because there can be holes in there.
4132 */ 4132 */
4133static void ext4_clear_blocks(handle_t *handle, struct inode *inode, 4133static int ext4_clear_blocks(handle_t *handle, struct inode *inode,
4134 struct buffer_head *bh, 4134 struct buffer_head *bh,
4135 ext4_fsblk_t block_to_free, 4135 ext4_fsblk_t block_to_free,
4136 unsigned long count, __le32 *first, 4136 unsigned long count, __le32 *first,
4137 __le32 *last) 4137 __le32 *last)
4138{ 4138{
4139 __le32 *p; 4139 __le32 *p;
4140 int flags = EXT4_FREE_BLOCKS_FORGET; 4140 int flags = EXT4_FREE_BLOCKS_FORGET | EXT4_FREE_BLOCKS_VALIDATED;
4141 4141
4142 if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)) 4142 if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode))
4143 flags |= EXT4_FREE_BLOCKS_METADATA; 4143 flags |= EXT4_FREE_BLOCKS_METADATA;
4144 4144
4145 if (!ext4_data_block_valid(EXT4_SB(inode->i_sb), block_to_free,
4146 count)) {
4147 ext4_error(inode->i_sb, __func__, "inode #%lu: "
4148 "attempt to clear blocks %llu len %lu, invalid",
4149 inode->i_ino, (unsigned long long) block_to_free,
4150 count);
4151 return 1;
4152 }
4153
4145 if (try_to_extend_transaction(handle, inode)) { 4154 if (try_to_extend_transaction(handle, inode)) {
4146 if (bh) { 4155 if (bh) {
4147 BUFFER_TRACE(bh, "call ext4_handle_dirty_metadata"); 4156 BUFFER_TRACE(bh, "call ext4_handle_dirty_metadata");
@@ -4160,6 +4169,7 @@ static void ext4_clear_blocks(handle_t *handle, struct inode *inode,
4160 *p = 0; 4169 *p = 0;
4161 4170
4162 ext4_free_blocks(handle, inode, 0, block_to_free, count, flags); 4171 ext4_free_blocks(handle, inode, 0, block_to_free, count, flags);
4172 return 0;
4163} 4173}
4164 4174
4165/** 4175/**
@@ -4215,9 +4225,10 @@ static void ext4_free_data(handle_t *handle, struct inode *inode,
4215 } else if (nr == block_to_free + count) { 4225 } else if (nr == block_to_free + count) {
4216 count++; 4226 count++;
4217 } else { 4227 } else {
4218 ext4_clear_blocks(handle, inode, this_bh, 4228 if (ext4_clear_blocks(handle, inode, this_bh,
4219 block_to_free, 4229 block_to_free, count,
4220 count, block_to_free_p, p); 4230 block_to_free_p, p))
4231 break;
4221 block_to_free = nr; 4232 block_to_free = nr;
4222 block_to_free_p = p; 4233 block_to_free_p = p;
4223 count = 1; 4234 count = 1;
@@ -4281,6 +4292,16 @@ static void ext4_free_branches(handle_t *handle, struct inode *inode,
4281 if (!nr) 4292 if (!nr)
4282 continue; /* A hole */ 4293 continue; /* A hole */
4283 4294
4295 if (!ext4_data_block_valid(EXT4_SB(inode->i_sb),
4296 nr, 1)) {
4297 ext4_error(inode->i_sb, __func__,
4298 "indirect mapped block in inode "
4299 "#%lu invalid (level %d, blk #%lu)",
4300 inode->i_ino, depth,
4301 (unsigned long) nr);
4302 break;
4303 }
4304
4284 /* Go read the buffer for the next level down */ 4305 /* Go read the buffer for the next level down */
4285 bh = sb_bread(inode->i_sb, nr); 4306 bh = sb_bread(inode->i_sb, nr);
4286 4307
diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c
index d34afad3e137..d129c1039f1d 100644
--- a/fs/ext4/mballoc.c
+++ b/fs/ext4/mballoc.c
@@ -4476,10 +4476,11 @@ void ext4_free_blocks(handle_t *handle, struct inode *inode,
4476 4476
4477 sbi = EXT4_SB(sb); 4477 sbi = EXT4_SB(sb);
4478 es = EXT4_SB(sb)->s_es; 4478 es = EXT4_SB(sb)->s_es;
4479 if (!ext4_data_block_valid(sbi, block, count)) { 4479 if (!(flags & EXT4_FREE_BLOCKS_VALIDATED) &&
4480 !ext4_data_block_valid(sbi, block, count)) {
4480 ext4_error(sb, __func__, 4481 ext4_error(sb, __func__,
4481 "Freeing blocks not in datazone - " 4482 "Freeing blocks not in datazone - "
4482 "block = %llu, count = %lu", block, count); 4483 "block = %llu, count = %lu", block, count);
4483 goto error_return; 4484 goto error_return;
4484 } 4485 }
4485 4486