aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ext4/inode.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/ext4/inode.c')
-rw-r--r--fs/ext4/inode.c47
1 files changed, 38 insertions, 9 deletions
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index d7b7480682b9..dadd3f995db5 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -372,20 +372,21 @@ static int ext4_block_to_path(struct inode *inode,
372} 372}
373 373
374static int __ext4_check_blockref(const char *function, struct inode *inode, 374static int __ext4_check_blockref(const char *function, struct inode *inode,
375 __le32 *p, unsigned int max) { 375 __le32 *p, unsigned int max)
376 376{
377 unsigned int maxblocks = ext4_blocks_count(EXT4_SB(inode->i_sb)->s_es);
378 __le32 *bref = p; 377 __le32 *bref = p;
378 unsigned int blk;
379
379 while (bref < p+max) { 380 while (bref < p+max) {
380 if (unlikely(le32_to_cpu(*bref) >= maxblocks)) { 381 blk = le32_to_cpu(*bref++);
382 if (blk &&
383 unlikely(!ext4_data_block_valid(EXT4_SB(inode->i_sb),
384 blk, 1))) {
381 ext4_error(inode->i_sb, function, 385 ext4_error(inode->i_sb, function,
382 "block reference %u >= max (%u) " 386 "invalid block reference %u "
383 "in inode #%lu, offset=%d", 387 "in inode #%lu", blk, inode->i_ino);
384 le32_to_cpu(*bref), maxblocks,
385 inode->i_ino, (int)(bref-p));
386 return -EIO; 388 return -EIO;
387 } 389 }
388 bref++;
389 } 390 }
390 return 0; 391 return 0;
391} 392}
@@ -1125,6 +1126,21 @@ static void ext4_da_update_reserve_space(struct inode *inode, int used)
1125 ext4_discard_preallocations(inode); 1126 ext4_discard_preallocations(inode);
1126} 1127}
1127 1128
1129static int check_block_validity(struct inode *inode, sector_t logical,
1130 sector_t phys, int len)
1131{
1132 if (!ext4_data_block_valid(EXT4_SB(inode->i_sb), phys, len)) {
1133 ext4_error(inode->i_sb, "check_block_validity",
1134 "inode #%lu logical block %llu mapped to %llu "
1135 "(size %d)", inode->i_ino,
1136 (unsigned long long) logical,
1137 (unsigned long long) phys, len);
1138 WARN_ON(1);
1139 return -EIO;
1140 }
1141 return 0;
1142}
1143
1128/* 1144/*
1129 * The ext4_get_blocks() function tries to look up the requested blocks, 1145 * The ext4_get_blocks() function tries to look up the requested blocks,
1130 * and returns if the blocks are already mapped. 1146 * and returns if the blocks are already mapped.
@@ -1170,6 +1186,13 @@ int ext4_get_blocks(handle_t *handle, struct inode *inode, sector_t block,
1170 } 1186 }
1171 up_read((&EXT4_I(inode)->i_data_sem)); 1187 up_read((&EXT4_I(inode)->i_data_sem));
1172 1188
1189 if (retval > 0 && buffer_mapped(bh)) {
1190 int ret = check_block_validity(inode, block,
1191 bh->b_blocknr, retval);
1192 if (ret != 0)
1193 return ret;
1194 }
1195
1173 /* If it is only a block(s) look up */ 1196 /* If it is only a block(s) look up */
1174 if ((flags & EXT4_GET_BLOCKS_CREATE) == 0) 1197 if ((flags & EXT4_GET_BLOCKS_CREATE) == 0)
1175 return retval; 1198 return retval;
@@ -1245,6 +1268,12 @@ int ext4_get_blocks(handle_t *handle, struct inode *inode, sector_t block,
1245 ext4_da_update_reserve_space(inode, retval); 1268 ext4_da_update_reserve_space(inode, retval);
1246 1269
1247 up_write((&EXT4_I(inode)->i_data_sem)); 1270 up_write((&EXT4_I(inode)->i_data_sem));
1271 if (retval > 0 && buffer_mapped(bh)) {
1272 int ret = check_block_validity(inode, block,
1273 bh->b_blocknr, retval);
1274 if (ret != 0)
1275 return ret;
1276 }
1248 return retval; 1277 return retval;
1249} 1278}
1250 1279