Commit b0336e8d2108e6302aecaadd17c6c0bd686da22d

Authored by Darrick J. Wong
Committed by Theodore Ts'o
1 parent dbe8944404

ext4: calculate and verify checksums of directory leaf blocks

Calculate and verify the checksums for directory leaf blocks
(i.e. blocks that only contain actual directory entries).  The
checksum lives in what looks to be an unused directory entry with a 0
name_len at the end of the block.  This scheme is not used for
internal htree nodes because the mechanism in place there only costs
one dx_entry, whereas the "empty" directory entry would cost two
dx_entries.

Signed-off-by: Darrick J. Wong <djwong@us.ibm.com>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>

Showing 3 changed files with 259 additions and 15 deletions Side-by-side Diff

... ... @@ -179,6 +179,18 @@
179 179 continue;
180 180 }
181 181  
  182 + /* Check the checksum */
  183 + if (!buffer_verified(bh) &&
  184 + !ext4_dirent_csum_verify(inode,
  185 + (struct ext4_dir_entry *)bh->b_data)) {
  186 + EXT4_ERROR_FILE(filp, 0, "directory fails checksum "
  187 + "at offset %llu",
  188 + (unsigned long long)filp->f_pos);
  189 + filp->f_pos += sb->s_blocksize - offset;
  190 + continue;
  191 + }
  192 + set_buffer_verified(bh);
  193 +
182 194 revalidate:
183 195 /* If the dir block has changed since the last call to
184 196 * readdir(2), then we might be pointing to an invalid
... ... @@ -2019,6 +2019,8 @@
2019 2019 extern int ext4_ext_migrate(struct inode *);
2020 2020  
2021 2021 /* namei.c */
  2022 +extern int ext4_dirent_csum_verify(struct inode *inode,
  2023 + struct ext4_dir_entry *dirent);
2022 2024 extern int ext4_orphan_add(handle_t *, struct inode *);
2023 2025 extern int ext4_orphan_del(handle_t *, struct inode *);
2024 2026 extern int ext4_htree_fill_tree(struct file *dir_file, __u32 start_hash,
... ... @@ -189,6 +189,115 @@
189 189 struct inode *inode);
190 190  
191 191 /* checksumming functions */
  192 +#define EXT4_DIRENT_TAIL(block, blocksize) \
  193 + ((struct ext4_dir_entry_tail *)(((void *)(block)) + \
  194 + ((blocksize) - \
  195 + sizeof(struct ext4_dir_entry_tail))))
  196 +
  197 +static void initialize_dirent_tail(struct ext4_dir_entry_tail *t,
  198 + unsigned int blocksize)
  199 +{
  200 + memset(t, 0, sizeof(struct ext4_dir_entry_tail));
  201 + t->det_rec_len = ext4_rec_len_to_disk(
  202 + sizeof(struct ext4_dir_entry_tail), blocksize);
  203 + t->det_reserved_ft = EXT4_FT_DIR_CSUM;
  204 +}
  205 +
  206 +/* Walk through a dirent block to find a checksum "dirent" at the tail */
  207 +static struct ext4_dir_entry_tail *get_dirent_tail(struct inode *inode,
  208 + struct ext4_dir_entry *de)
  209 +{
  210 + struct ext4_dir_entry_tail *t;
  211 +
  212 +#ifdef PARANOID
  213 + struct ext4_dir_entry *d, *top;
  214 +
  215 + d = de;
  216 + top = (struct ext4_dir_entry *)(((void *)de) +
  217 + (EXT4_BLOCK_SIZE(inode->i_sb) -
  218 + sizeof(struct ext4_dir_entry_tail)));
  219 + while (d < top && d->rec_len)
  220 + d = (struct ext4_dir_entry *)(((void *)d) +
  221 + le16_to_cpu(d->rec_len));
  222 +
  223 + if (d != top)
  224 + return NULL;
  225 +
  226 + t = (struct ext4_dir_entry_tail *)d;
  227 +#else
  228 + t = EXT4_DIRENT_TAIL(de, EXT4_BLOCK_SIZE(inode->i_sb));
  229 +#endif
  230 +
  231 + if (t->det_reserved_zero1 ||
  232 + le16_to_cpu(t->det_rec_len) != sizeof(struct ext4_dir_entry_tail) ||
  233 + t->det_reserved_zero2 ||
  234 + t->det_reserved_ft != EXT4_FT_DIR_CSUM)
  235 + return NULL;
  236 +
  237 + return t;
  238 +}
  239 +
  240 +static __le32 ext4_dirent_csum(struct inode *inode,
  241 + struct ext4_dir_entry *dirent, int size)
  242 +{
  243 + struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
  244 + struct ext4_inode_info *ei = EXT4_I(inode);
  245 + __u32 csum;
  246 +
  247 + csum = ext4_chksum(sbi, ei->i_csum_seed, (__u8 *)dirent, size);
  248 + return cpu_to_le32(csum);
  249 +}
  250 +
  251 +int ext4_dirent_csum_verify(struct inode *inode, struct ext4_dir_entry *dirent)
  252 +{
  253 + struct ext4_dir_entry_tail *t;
  254 +
  255 + if (!EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb,
  256 + EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
  257 + return 1;
  258 +
  259 + t = get_dirent_tail(inode, dirent);
  260 + if (!t) {
  261 + EXT4_ERROR_INODE(inode, "metadata_csum set but no space in dir "
  262 + "leaf for checksum. Please run e2fsck -D.");
  263 + return 0;
  264 + }
  265 +
  266 + if (t->det_checksum != ext4_dirent_csum(inode, dirent,
  267 + (void *)t - (void *)dirent))
  268 + return 0;
  269 +
  270 + return 1;
  271 +}
  272 +
  273 +static void ext4_dirent_csum_set(struct inode *inode,
  274 + struct ext4_dir_entry *dirent)
  275 +{
  276 + struct ext4_dir_entry_tail *t;
  277 +
  278 + if (!EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb,
  279 + EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
  280 + return;
  281 +
  282 + t = get_dirent_tail(inode, dirent);
  283 + if (!t) {
  284 + EXT4_ERROR_INODE(inode, "metadata_csum set but no space in dir "
  285 + "leaf for checksum. Please run e2fsck -D.");
  286 + return;
  287 + }
  288 +
  289 + t->det_checksum = ext4_dirent_csum(inode, dirent,
  290 + (void *)t - (void *)dirent);
  291 +}
  292 +
  293 +static inline int ext4_handle_dirty_dirent_node(handle_t *handle,
  294 + struct inode *inode,
  295 + struct buffer_head *bh)
  296 +{
  297 + ext4_dirent_csum_set(inode, (struct ext4_dir_entry *)bh->b_data);
  298 + return ext4_handle_dirty_metadata(handle, inode, bh);
  299 +}
  300 +
192 301 static struct dx_countlimit *get_dx_countlimit(struct inode *inode,
193 302 struct ext4_dir_entry *dirent,
194 303 int *offset)
... ... @@ -737,6 +846,11 @@
737 846 if (!(bh = ext4_bread (NULL, dir, block, 0, &err)))
738 847 return err;
739 848  
  849 + if (!buffer_verified(bh) &&
  850 + !ext4_dirent_csum_verify(dir, (struct ext4_dir_entry *)bh->b_data))
  851 + return -EIO;
  852 + set_buffer_verified(bh);
  853 +
740 854 de = (struct ext4_dir_entry_2 *) bh->b_data;
741 855 top = (struct ext4_dir_entry_2 *) ((char *) de +
742 856 dir->i_sb->s_blocksize -
... ... @@ -1096,6 +1210,15 @@
1096 1210 brelse(bh);
1097 1211 goto next;
1098 1212 }
  1213 + if (!buffer_verified(bh) &&
  1214 + !ext4_dirent_csum_verify(dir,
  1215 + (struct ext4_dir_entry *)bh->b_data)) {
  1216 + EXT4_ERROR_INODE(dir, "checksumming directory "
  1217 + "block %lu", (unsigned long)block);
  1218 + brelse(bh);
  1219 + goto next;
  1220 + }
  1221 + set_buffer_verified(bh);
1099 1222 i = search_dirblock(bh, dir, d_name,
1100 1223 block << EXT4_BLOCK_SIZE_BITS(sb), res_dir);
1101 1224 if (i == 1) {
... ... @@ -1147,6 +1270,16 @@
1147 1270 if (!(bh = ext4_bread(NULL, dir, block, 0, err)))
1148 1271 goto errout;
1149 1272  
  1273 + if (!buffer_verified(bh) &&
  1274 + !ext4_dirent_csum_verify(dir,
  1275 + (struct ext4_dir_entry *)bh->b_data)) {
  1276 + EXT4_ERROR_INODE(dir, "checksumming directory "
  1277 + "block %lu", (unsigned long)block);
  1278 + brelse(bh);
  1279 + *err = -EIO;
  1280 + goto errout;
  1281 + }
  1282 + set_buffer_verified(bh);
1150 1283 retval = search_dirblock(bh, dir, d_name,
1151 1284 block << EXT4_BLOCK_SIZE_BITS(sb),
1152 1285 res_dir);
1153 1286  
... ... @@ -1319,8 +1452,14 @@
1319 1452 char *data1 = (*bh)->b_data, *data2;
1320 1453 unsigned split, move, size;
1321 1454 struct ext4_dir_entry_2 *de = NULL, *de2;
  1455 + struct ext4_dir_entry_tail *t;
  1456 + int csum_size = 0;
1322 1457 int err = 0, i;
1323 1458  
  1459 + if (EXT4_HAS_RO_COMPAT_FEATURE(dir->i_sb,
  1460 + EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
  1461 + csum_size = sizeof(struct ext4_dir_entry_tail);
  1462 +
1324 1463 bh2 = ext4_append (handle, dir, &newblock, &err);
1325 1464 if (!(bh2)) {
1326 1465 brelse(*bh);
1327 1466  
1328 1467  
... ... @@ -1367,10 +1506,20 @@
1367 1506 /* Fancy dance to stay within two buffers */
1368 1507 de2 = dx_move_dirents(data1, data2, map + split, count - split, blocksize);
1369 1508 de = dx_pack_dirents(data1, blocksize);
1370   - de->rec_len = ext4_rec_len_to_disk(data1 + blocksize - (char *) de,
  1509 + de->rec_len = ext4_rec_len_to_disk(data1 + (blocksize - csum_size) -
  1510 + (char *) de,
1371 1511 blocksize);
1372   - de2->rec_len = ext4_rec_len_to_disk(data2 + blocksize - (char *) de2,
  1512 + de2->rec_len = ext4_rec_len_to_disk(data2 + (blocksize - csum_size) -
  1513 + (char *) de2,
1373 1514 blocksize);
  1515 + if (csum_size) {
  1516 + t = EXT4_DIRENT_TAIL(data2, blocksize);
  1517 + initialize_dirent_tail(t, blocksize);
  1518 +
  1519 + t = EXT4_DIRENT_TAIL(data1, blocksize);
  1520 + initialize_dirent_tail(t, blocksize);
  1521 + }
  1522 +
1374 1523 dxtrace(dx_show_leaf (hinfo, (struct ext4_dir_entry_2 *) data1, blocksize, 1));
1375 1524 dxtrace(dx_show_leaf (hinfo, (struct ext4_dir_entry_2 *) data2, blocksize, 1));
1376 1525  
... ... @@ -1381,7 +1530,7 @@
1381 1530 de = de2;
1382 1531 }
1383 1532 dx_insert_block(frame, hash2 + continued, newblock);
1384   - err = ext4_handle_dirty_metadata(handle, dir, bh2);
  1533 + err = ext4_handle_dirty_dirent_node(handle, dir, bh2);
1385 1534 if (err)
1386 1535 goto journal_error;
1387 1536 err = ext4_handle_dirty_dx_node(handle, dir, frame->bh);
1388 1537  
1389 1538  
... ... @@ -1421,11 +1570,16 @@
1421 1570 unsigned short reclen;
1422 1571 int nlen, rlen, err;
1423 1572 char *top;
  1573 + int csum_size = 0;
1424 1574  
  1575 + if (EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb,
  1576 + EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
  1577 + csum_size = sizeof(struct ext4_dir_entry_tail);
  1578 +
1425 1579 reclen = EXT4_DIR_REC_LEN(namelen);
1426 1580 if (!de) {
1427 1581 de = (struct ext4_dir_entry_2 *)bh->b_data;
1428   - top = bh->b_data + blocksize - reclen;
  1582 + top = bh->b_data + (blocksize - csum_size) - reclen;
1429 1583 while ((char *) de <= top) {
1430 1584 if (ext4_check_dir_entry(dir, NULL, de, bh, offset))
1431 1585 return -EIO;
... ... @@ -1481,7 +1635,7 @@
1481 1635 dir->i_version++;
1482 1636 ext4_mark_inode_dirty(handle, dir);
1483 1637 BUFFER_TRACE(bh, "call ext4_handle_dirty_metadata");
1484   - err = ext4_handle_dirty_metadata(handle, dir, bh);
  1638 + err = ext4_handle_dirty_dirent_node(handle, dir, bh);
1485 1639 if (err)
1486 1640 ext4_std_error(dir->i_sb, err);
1487 1641 return 0;
... ... @@ -1502,6 +1656,7 @@
1502 1656 struct dx_frame frames[2], *frame;
1503 1657 struct dx_entry *entries;
1504 1658 struct ext4_dir_entry_2 *de, *de2;
  1659 + struct ext4_dir_entry_tail *t;
1505 1660 char *data1, *top;
1506 1661 unsigned len;
1507 1662 int retval;
1508 1663  
... ... @@ -1509,7 +1664,12 @@
1509 1664 struct dx_hash_info hinfo;
1510 1665 ext4_lblk_t block;
1511 1666 struct fake_dirent *fde;
  1667 + int csum_size = 0;
1512 1668  
  1669 + if (EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb,
  1670 + EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
  1671 + csum_size = sizeof(struct ext4_dir_entry_tail);
  1672 +
1513 1673 blocksize = dir->i_sb->s_blocksize;
1514 1674 dxtrace(printk(KERN_DEBUG "Creating index: inode %lu\n", dir->i_ino));
1515 1675 retval = ext4_journal_get_write_access(handle, bh);
... ... @@ -1529,7 +1689,7 @@
1529 1689 brelse(bh);
1530 1690 return -EIO;
1531 1691 }
1532   - len = ((char *) root) + blocksize - (char *) de;
  1692 + len = ((char *) root) + (blocksize - csum_size) - (char *) de;
1533 1693  
1534 1694 /* Allocate new block for the 0th block's dirents */
1535 1695 bh2 = ext4_append(handle, dir, &block, &retval);
1536 1696  
... ... @@ -1545,8 +1705,15 @@
1545 1705 top = data1 + len;
1546 1706 while ((char *)(de2 = ext4_next_entry(de, blocksize)) < top)
1547 1707 de = de2;
1548   - de->rec_len = ext4_rec_len_to_disk(data1 + blocksize - (char *) de,
  1708 + de->rec_len = ext4_rec_len_to_disk(data1 + (blocksize - csum_size) -
  1709 + (char *) de,
1549 1710 blocksize);
  1711 +
  1712 + if (csum_size) {
  1713 + t = EXT4_DIRENT_TAIL(data1, blocksize);
  1714 + initialize_dirent_tail(t, blocksize);
  1715 + }
  1716 +
1550 1717 /* Initialize the root; the dot dirents already exist */
1551 1718 de = (struct ext4_dir_entry_2 *) (&root->dotdot);
1552 1719 de->rec_len = ext4_rec_len_to_disk(blocksize - EXT4_DIR_REC_LEN(2),
... ... @@ -1572,7 +1739,7 @@
1572 1739 bh = bh2;
1573 1740  
1574 1741 ext4_handle_dirty_dx_node(handle, dir, frame->bh);
1575   - ext4_handle_dirty_metadata(handle, dir, bh);
  1742 + ext4_handle_dirty_dirent_node(handle, dir, bh);
1576 1743  
1577 1744 de = do_split(handle,dir, &bh, frame, &hinfo, &retval);
1578 1745 if (!de) {
1579 1746  
1580 1747  
... ... @@ -1608,12 +1775,18 @@
1608 1775 struct inode *dir = dentry->d_parent->d_inode;
1609 1776 struct buffer_head *bh;
1610 1777 struct ext4_dir_entry_2 *de;
  1778 + struct ext4_dir_entry_tail *t;
1611 1779 struct super_block *sb;
1612 1780 int retval;
1613 1781 int dx_fallback=0;
1614 1782 unsigned blocksize;
1615 1783 ext4_lblk_t block, blocks;
  1784 + int csum_size = 0;
1616 1785  
  1786 + if (EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb,
  1787 + EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
  1788 + csum_size = sizeof(struct ext4_dir_entry_tail);
  1789 +
1617 1790 sb = dir->i_sb;
1618 1791 blocksize = sb->s_blocksize;
1619 1792 if (!dentry->d_name.len)
... ... @@ -1631,6 +1804,11 @@
1631 1804 bh = ext4_bread(handle, dir, block, 0, &retval);
1632 1805 if(!bh)
1633 1806 return retval;
  1807 + if (!buffer_verified(bh) &&
  1808 + !ext4_dirent_csum_verify(dir,
  1809 + (struct ext4_dir_entry *)bh->b_data))
  1810 + return -EIO;
  1811 + set_buffer_verified(bh);
1634 1812 retval = add_dirent_to_buf(handle, dentry, inode, NULL, bh);
1635 1813 if (retval != -ENOSPC) {
1636 1814 brelse(bh);
... ... @@ -1647,7 +1825,13 @@
1647 1825 return retval;
1648 1826 de = (struct ext4_dir_entry_2 *) bh->b_data;
1649 1827 de->inode = 0;
1650   - de->rec_len = ext4_rec_len_to_disk(blocksize, blocksize);
  1828 + de->rec_len = ext4_rec_len_to_disk(blocksize - csum_size, blocksize);
  1829 +
  1830 + if (csum_size) {
  1831 + t = EXT4_DIRENT_TAIL(bh->b_data, blocksize);
  1832 + initialize_dirent_tail(t, blocksize);
  1833 + }
  1834 +
1651 1835 retval = add_dirent_to_buf(handle, dentry, inode, de, bh);
1652 1836 brelse(bh);
1653 1837 if (retval == 0)
... ... @@ -1679,6 +1863,11 @@
1679 1863 if (!(bh = ext4_bread(handle,dir, dx_get_block(frame->at), 0, &err)))
1680 1864 goto cleanup;
1681 1865  
  1866 + if (!buffer_verified(bh) &&
  1867 + !ext4_dirent_csum_verify(dir, (struct ext4_dir_entry *)bh->b_data))
  1868 + goto journal_error;
  1869 + set_buffer_verified(bh);
  1870 +
1682 1871 BUFFER_TRACE(bh, "get_write_access");
1683 1872 err = ext4_journal_get_write_access(handle, bh);
1684 1873 if (err)
1685 1874  
1686 1875  
... ... @@ -1804,12 +1993,17 @@
1804 1993 {
1805 1994 struct ext4_dir_entry_2 *de, *pde;
1806 1995 unsigned int blocksize = dir->i_sb->s_blocksize;
  1996 + int csum_size = 0;
1807 1997 int i, err;
1808 1998  
  1999 + if (EXT4_HAS_RO_COMPAT_FEATURE(dir->i_sb,
  2000 + EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
  2001 + csum_size = sizeof(struct ext4_dir_entry_tail);
  2002 +
1809 2003 i = 0;
1810 2004 pde = NULL;
1811 2005 de = (struct ext4_dir_entry_2 *) bh->b_data;
1812   - while (i < bh->b_size) {
  2006 + while (i < bh->b_size - csum_size) {
1813 2007 if (ext4_check_dir_entry(dir, NULL, de, bh, i))
1814 2008 return -EIO;
1815 2009 if (de == de_del) {
... ... @@ -1830,7 +2024,7 @@
1830 2024 de->inode = 0;
1831 2025 dir->i_version++;
1832 2026 BUFFER_TRACE(bh, "call ext4_handle_dirty_metadata");
1833   - err = ext4_handle_dirty_metadata(handle, dir, bh);
  2027 + err = ext4_handle_dirty_dirent_node(handle, dir, bh);
1834 2028 if (unlikely(err)) {
1835 2029 ext4_std_error(dir->i_sb, err);
1836 2030 return err;
1837 2031  
1838 2032  
... ... @@ -1972,9 +2166,15 @@
1972 2166 struct inode *inode;
1973 2167 struct buffer_head *dir_block = NULL;
1974 2168 struct ext4_dir_entry_2 *de;
  2169 + struct ext4_dir_entry_tail *t;
1975 2170 unsigned int blocksize = dir->i_sb->s_blocksize;
  2171 + int csum_size = 0;
1976 2172 int err, retries = 0;
1977 2173  
  2174 + if (EXT4_HAS_RO_COMPAT_FEATURE(dir->i_sb,
  2175 + EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
  2176 + csum_size = sizeof(struct ext4_dir_entry_tail);
  2177 +
1978 2178 if (EXT4_DIR_LINK_MAX(dir))
1979 2179 return -EMLINK;
1980 2180  
1981 2181  
1982 2182  
1983 2183  
... ... @@ -2015,16 +2215,24 @@
2015 2215 ext4_set_de_type(dir->i_sb, de, S_IFDIR);
2016 2216 de = ext4_next_entry(de, blocksize);
2017 2217 de->inode = cpu_to_le32(dir->i_ino);
2018   - de->rec_len = ext4_rec_len_to_disk(blocksize - EXT4_DIR_REC_LEN(1),
  2218 + de->rec_len = ext4_rec_len_to_disk(blocksize -
  2219 + (csum_size + EXT4_DIR_REC_LEN(1)),
2019 2220 blocksize);
2020 2221 de->name_len = 2;
2021 2222 strcpy(de->name, "..");
2022 2223 ext4_set_de_type(dir->i_sb, de, S_IFDIR);
2023 2224 set_nlink(inode, 2);
  2225 +
  2226 + if (csum_size) {
  2227 + t = EXT4_DIRENT_TAIL(dir_block->b_data, blocksize);
  2228 + initialize_dirent_tail(t, blocksize);
  2229 + }
  2230 +
2024 2231 BUFFER_TRACE(dir_block, "call ext4_handle_dirty_metadata");
2025   - err = ext4_handle_dirty_metadata(handle, inode, dir_block);
  2232 + err = ext4_handle_dirty_dirent_node(handle, inode, dir_block);
2026 2233 if (err)
2027 2234 goto out_clear_inode;
  2235 + set_buffer_verified(dir_block);
2028 2236 err = ext4_mark_inode_dirty(handle, inode);
2029 2237 if (!err)
2030 2238 err = ext4_add_entry(handle, dentry, inode);
... ... @@ -2074,6 +2282,14 @@
2074 2282 inode->i_ino);
2075 2283 return 1;
2076 2284 }
  2285 + if (!buffer_verified(bh) &&
  2286 + !ext4_dirent_csum_verify(inode,
  2287 + (struct ext4_dir_entry *)bh->b_data)) {
  2288 + EXT4_ERROR_INODE(inode, "checksum error reading directory "
  2289 + "lblock 0");
  2290 + return -EIO;
  2291 + }
  2292 + set_buffer_verified(bh);
2077 2293 de = (struct ext4_dir_entry_2 *) bh->b_data;
2078 2294 de1 = ext4_next_entry(de, sb->s_blocksize);
2079 2295 if (le32_to_cpu(de->inode) != inode->i_ino ||
... ... @@ -2105,6 +2321,14 @@
2105 2321 offset += sb->s_blocksize;
2106 2322 continue;
2107 2323 }
  2324 + if (!buffer_verified(bh) &&
  2325 + !ext4_dirent_csum_verify(inode,
  2326 + (struct ext4_dir_entry *)bh->b_data)) {
  2327 + EXT4_ERROR_INODE(inode, "checksum error "
  2328 + "reading directory lblock 0");
  2329 + return -EIO;
  2330 + }
  2331 + set_buffer_verified(bh);
2108 2332 de = (struct ext4_dir_entry_2 *) bh->b_data;
2109 2333 }
2110 2334 if (ext4_check_dir_entry(inode, NULL, de, bh, offset)) {
... ... @@ -2605,6 +2829,11 @@
2605 2829 dir_bh = ext4_bread(handle, old_inode, 0, 0, &retval);
2606 2830 if (!dir_bh)
2607 2831 goto end_rename;
  2832 + if (!buffer_verified(dir_bh) &&
  2833 + !ext4_dirent_csum_verify(old_inode,
  2834 + (struct ext4_dir_entry *)dir_bh->b_data))
  2835 + goto end_rename;
  2836 + set_buffer_verified(dir_bh);
2608 2837 if (le32_to_cpu(PARENT_INO(dir_bh->b_data,
2609 2838 old_dir->i_sb->s_blocksize)) != old_dir->i_ino)
2610 2839 goto end_rename;
... ... @@ -2635,7 +2864,7 @@
2635 2864 ext4_current_time(new_dir);
2636 2865 ext4_mark_inode_dirty(handle, new_dir);
2637 2866 BUFFER_TRACE(new_bh, "call ext4_handle_dirty_metadata");
2638   - retval = ext4_handle_dirty_metadata(handle, new_dir, new_bh);
  2867 + retval = ext4_handle_dirty_dirent_node(handle, new_dir, new_bh);
2639 2868 if (unlikely(retval)) {
2640 2869 ext4_std_error(new_dir->i_sb, retval);
2641 2870 goto end_rename;
... ... @@ -2689,7 +2918,8 @@
2689 2918 PARENT_INO(dir_bh->b_data, new_dir->i_sb->s_blocksize) =
2690 2919 cpu_to_le32(new_dir->i_ino);
2691 2920 BUFFER_TRACE(dir_bh, "call ext4_handle_dirty_metadata");
2692   - retval = ext4_handle_dirty_metadata(handle, old_inode, dir_bh);
  2921 + retval = ext4_handle_dirty_dirent_node(handle, old_inode,
  2922 + dir_bh);
2693 2923 if (retval) {
2694 2924 ext4_std_error(old_dir->i_sb, retval);
2695 2925 goto end_rename;