aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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: