aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteven Whitehouse <swhiteho@redhat.com>2007-04-18 04:38:42 -0400
committerSteven Whitehouse <swhiteho@redhat.com>2007-05-01 04:11:30 -0400
commitbdd19a22f85a7039e01accd8717eaec4addd9dfd (patch)
tree6c0367cb96582f87432047ea92e3a67eaeef3635
parent7a0079d9e3fe8826475a08785f3d348c4b509774 (diff)
[GFS2] Patch to detect corrupt number of dir entries in leaf and/or inode blocks
This patch detects when the number of entries in a leaf block or inode block (in the case of stuffed directories) is corrupt and informs the user. It prevents us from running off the end of the array thats been allocated for the sorting in this case, Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
-rw-r--r--fs/gfs2/dir.c35
1 files changed, 30 insertions, 5 deletions
diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c
index 82a1ac7895a2..6c3ed7674a9f 100644
--- a/fs/gfs2/dir.c
+++ b/fs/gfs2/dir.c
@@ -1262,9 +1262,10 @@ static int gfs2_dir_read_leaf(struct inode *inode, u64 *offset, void *opaque,
1262 u64 leaf_no) 1262 u64 leaf_no)
1263{ 1263{
1264 struct gfs2_inode *ip = GFS2_I(inode); 1264 struct gfs2_inode *ip = GFS2_I(inode);
1265 struct gfs2_sbd *sdp = GFS2_SB(inode);
1265 struct buffer_head *bh; 1266 struct buffer_head *bh;
1266 struct gfs2_leaf *lf; 1267 struct gfs2_leaf *lf;
1267 unsigned entries = 0; 1268 unsigned entries = 0, entries2 = 0;
1268 unsigned leaves = 0; 1269 unsigned leaves = 0;
1269 const struct gfs2_dirent **darr, *dent; 1270 const struct gfs2_dirent **darr, *dent;
1270 struct dirent_gather g; 1271 struct dirent_gather g;
@@ -1290,7 +1291,13 @@ static int gfs2_dir_read_leaf(struct inode *inode, u64 *offset, void *opaque,
1290 return 0; 1291 return 0;
1291 1292
1292 error = -ENOMEM; 1293 error = -ENOMEM;
1293 larr = vmalloc((leaves + entries) * sizeof(void *)); 1294 /*
1295 * The extra 99 entries are not normally used, but are a buffer
1296 * zone in case the number of entries in the leaf is corrupt.
1297 * 99 is the maximum number of entries that can fit in a single
1298 * leaf block.
1299 */
1300 larr = vmalloc((leaves + entries + 99) * sizeof(void *));
1294 if (!larr) 1301 if (!larr)
1295 goto out; 1302 goto out;
1296 darr = (const struct gfs2_dirent **)(larr + leaves); 1303 darr = (const struct gfs2_dirent **)(larr + leaves);
@@ -1305,10 +1312,18 @@ static int gfs2_dir_read_leaf(struct inode *inode, u64 *offset, void *opaque,
1305 lf = (struct gfs2_leaf *)bh->b_data; 1312 lf = (struct gfs2_leaf *)bh->b_data;
1306 lfn = be64_to_cpu(lf->lf_next); 1313 lfn = be64_to_cpu(lf->lf_next);
1307 if (lf->lf_entries) { 1314 if (lf->lf_entries) {
1315 entries2 += be16_to_cpu(lf->lf_entries);
1308 dent = gfs2_dirent_scan(inode, bh->b_data, bh->b_size, 1316 dent = gfs2_dirent_scan(inode, bh->b_data, bh->b_size,
1309 gfs2_dirent_gather, NULL, &g); 1317 gfs2_dirent_gather, NULL, &g);
1310 error = PTR_ERR(dent); 1318 error = PTR_ERR(dent);
1311 if (IS_ERR(dent)) { 1319 if (IS_ERR(dent))
1320 goto out_kfree;
1321 if (entries2 != g.offset) {
1322 fs_warn(sdp, "Number of entries corrupt in dir leaf %llu, "
1323 "entries2 (%u) != g.offset (%u)\n",
1324 (u64)bh->b_blocknr, entries2, g.offset);
1325
1326 error = -EIO;
1312 goto out_kfree; 1327 goto out_kfree;
1313 } 1328 }
1314 error = 0; 1329 error = 0;
@@ -1318,6 +1333,7 @@ static int gfs2_dir_read_leaf(struct inode *inode, u64 *offset, void *opaque,
1318 } 1333 }
1319 } while(lfn); 1334 } while(lfn);
1320 1335
1336 BUG_ON(entries2 != entries);
1321 error = do_filldir_main(ip, offset, opaque, filldir, darr, 1337 error = do_filldir_main(ip, offset, opaque, filldir, darr,
1322 entries, copied); 1338 entries, copied);
1323out_kfree: 1339out_kfree:
@@ -1401,6 +1417,7 @@ int gfs2_dir_read(struct inode *inode, u64 *offset, void *opaque,
1401 filldir_t filldir) 1417 filldir_t filldir)
1402{ 1418{
1403 struct gfs2_inode *dip = GFS2_I(inode); 1419 struct gfs2_inode *dip = GFS2_I(inode);
1420 struct gfs2_sbd *sdp = GFS2_SB(inode);
1404 struct dirent_gather g; 1421 struct dirent_gather g;
1405 const struct gfs2_dirent **darr, *dent; 1422 const struct gfs2_dirent **darr, *dent;
1406 struct buffer_head *dibh; 1423 struct buffer_head *dibh;
@@ -1423,8 +1440,8 @@ int gfs2_dir_read(struct inode *inode, u64 *offset, void *opaque,
1423 return error; 1440 return error;
1424 1441
1425 error = -ENOMEM; 1442 error = -ENOMEM;
1426 darr = kmalloc(dip->i_di.di_entries * sizeof(struct gfs2_dirent *), 1443 /* 96 is max number of dirents which can be stuffed into an inode */
1427 GFP_KERNEL); 1444 darr = kmalloc(96 * sizeof(struct gfs2_dirent *), GFP_KERNEL);
1428 if (darr) { 1445 if (darr) {
1429 g.pdent = darr; 1446 g.pdent = darr;
1430 g.offset = 0; 1447 g.offset = 0;
@@ -1434,6 +1451,14 @@ int gfs2_dir_read(struct inode *inode, u64 *offset, void *opaque,
1434 error = PTR_ERR(dent); 1451 error = PTR_ERR(dent);
1435 goto out; 1452 goto out;
1436 } 1453 }
1454 if (dip->i_di.di_entries != g.offset) {
1455 fs_warn(sdp, "Number of entries corrupt in dir %llu, "
1456 "ip->i_di.di_entries (%u) != g.offset (%u)\n",
1457 dip->i_num.no_addr, dip->i_di.di_entries,
1458 g.offset);
1459 error = -EIO;
1460 goto out;
1461 }
1437 error = do_filldir_main(dip, offset, opaque, filldir, darr, 1462 error = do_filldir_main(dip, offset, opaque, filldir, darr,
1438 dip->i_di.di_entries, &copied); 1463 dip->i_di.di_entries, &copied);
1439out: 1464out: