diff options
author | Tao Ma <boyu.mt@taobao.com> | 2012-12-10 14:05:58 -0500 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2012-12-10 14:05:58 -0500 |
commit | 978fef914a2e6b8ad5672d0a39f9201b7aa7c396 (patch) | |
tree | 1b86969eeb25b92d1b206d9168bd4bf309537c0c | |
parent | 226ba972b0863783ad377f741f6ff0538f31ab00 (diff) |
ext4: create __ext4_insert_dentry for dir entry insertion
The old add_dirent_to_buf handles all the work related to the
work of adding dir entry to a dir block. Now we have inline data,
so create 2 new function __ext4_find_dest_de and __ext4_insert_dentry
that do the real work and let add_dirent_to_buf call them.
Signed-off-by: Tao Ma <boyu.mt@taobao.com>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
-rw-r--r-- | fs/ext4/ext4.h | 15 | ||||
-rw-r--r-- | fs/ext4/namei.c | 105 |
2 files changed, 80 insertions, 40 deletions
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index 59cbf498fd5f..8e9e94cf1bca 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h | |||
@@ -1969,6 +1969,21 @@ extern int ext4_htree_store_dirent(struct file *dir_file, __u32 hash, | |||
1969 | __u32 minor_hash, | 1969 | __u32 minor_hash, |
1970 | struct ext4_dir_entry_2 *dirent); | 1970 | struct ext4_dir_entry_2 *dirent); |
1971 | extern void ext4_htree_free_dir_info(struct dir_private_info *p); | 1971 | extern void ext4_htree_free_dir_info(struct dir_private_info *p); |
1972 | extern int ext4_find_dest_de(struct inode *dir, struct inode *inode, | ||
1973 | struct buffer_head *bh, | ||
1974 | void *buf, int buf_size, | ||
1975 | const char *name, int namelen, | ||
1976 | struct ext4_dir_entry_2 **dest_de); | ||
1977 | void ext4_insert_dentry(struct inode *inode, | ||
1978 | struct ext4_dir_entry_2 *de, | ||
1979 | int buf_size, | ||
1980 | const char *name, int namelen); | ||
1981 | static inline void ext4_update_dx_flag(struct inode *inode) | ||
1982 | { | ||
1983 | if (!EXT4_HAS_COMPAT_FEATURE(inode->i_sb, | ||
1984 | EXT4_FEATURE_COMPAT_DIR_INDEX)) | ||
1985 | ext4_clear_inode_flag(inode, EXT4_INODE_INDEX); | ||
1986 | } | ||
1972 | 1987 | ||
1973 | /* fsync.c */ | 1988 | /* fsync.c */ |
1974 | extern int ext4_sync_file(struct file *, loff_t, loff_t, int); | 1989 | extern int ext4_sync_file(struct file *, loff_t, loff_t, int); |
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index 10da2d50a5d8..bb9259d20b55 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c | |||
@@ -1084,13 +1084,6 @@ static void dx_insert_block(struct dx_frame *frame, u32 hash, ext4_lblk_t block) | |||
1084 | dx_set_count(entries, count + 1); | 1084 | dx_set_count(entries, count + 1); |
1085 | } | 1085 | } |
1086 | 1086 | ||
1087 | static void ext4_update_dx_flag(struct inode *inode) | ||
1088 | { | ||
1089 | if (!EXT4_HAS_COMPAT_FEATURE(inode->i_sb, | ||
1090 | EXT4_FEATURE_COMPAT_DIR_INDEX)) | ||
1091 | ext4_clear_inode_flag(inode, EXT4_INODE_INDEX); | ||
1092 | } | ||
1093 | |||
1094 | /* | 1087 | /* |
1095 | * NOTE! unlike strncmp, ext4_match returns 1 for success, 0 for failure. | 1088 | * NOTE! unlike strncmp, ext4_match returns 1 for success, 0 for failure. |
1096 | * | 1089 | * |
@@ -1614,6 +1607,63 @@ errout: | |||
1614 | return NULL; | 1607 | return NULL; |
1615 | } | 1608 | } |
1616 | 1609 | ||
1610 | int ext4_find_dest_de(struct inode *dir, struct inode *inode, | ||
1611 | struct buffer_head *bh, | ||
1612 | void *buf, int buf_size, | ||
1613 | const char *name, int namelen, | ||
1614 | struct ext4_dir_entry_2 **dest_de) | ||
1615 | { | ||
1616 | struct ext4_dir_entry_2 *de; | ||
1617 | unsigned short reclen = EXT4_DIR_REC_LEN(namelen); | ||
1618 | int nlen, rlen; | ||
1619 | unsigned int offset = 0; | ||
1620 | char *top; | ||
1621 | |||
1622 | de = (struct ext4_dir_entry_2 *)buf; | ||
1623 | top = buf + buf_size - reclen; | ||
1624 | while ((char *) de <= top) { | ||
1625 | if (ext4_check_dir_entry(dir, NULL, de, bh, | ||
1626 | buf, buf_size, offset)) | ||
1627 | return -EIO; | ||
1628 | if (ext4_match(namelen, name, de)) | ||
1629 | return -EEXIST; | ||
1630 | nlen = EXT4_DIR_REC_LEN(de->name_len); | ||
1631 | rlen = ext4_rec_len_from_disk(de->rec_len, buf_size); | ||
1632 | if ((de->inode ? rlen - nlen : rlen) >= reclen) | ||
1633 | break; | ||
1634 | de = (struct ext4_dir_entry_2 *)((char *)de + rlen); | ||
1635 | offset += rlen; | ||
1636 | } | ||
1637 | if ((char *) de > top) | ||
1638 | return -ENOSPC; | ||
1639 | |||
1640 | *dest_de = de; | ||
1641 | return 0; | ||
1642 | } | ||
1643 | |||
1644 | void ext4_insert_dentry(struct inode *inode, | ||
1645 | struct ext4_dir_entry_2 *de, | ||
1646 | int buf_size, | ||
1647 | const char *name, int namelen) | ||
1648 | { | ||
1649 | |||
1650 | int nlen, rlen; | ||
1651 | |||
1652 | nlen = EXT4_DIR_REC_LEN(de->name_len); | ||
1653 | rlen = ext4_rec_len_from_disk(de->rec_len, buf_size); | ||
1654 | if (de->inode) { | ||
1655 | struct ext4_dir_entry_2 *de1 = | ||
1656 | (struct ext4_dir_entry_2 *)((char *)de + nlen); | ||
1657 | de1->rec_len = ext4_rec_len_to_disk(rlen - nlen, buf_size); | ||
1658 | de->rec_len = ext4_rec_len_to_disk(nlen, buf_size); | ||
1659 | de = de1; | ||
1660 | } | ||
1661 | de->file_type = EXT4_FT_UNKNOWN; | ||
1662 | de->inode = cpu_to_le32(inode->i_ino); | ||
1663 | ext4_set_de_type(inode->i_sb, de, inode->i_mode); | ||
1664 | de->name_len = namelen; | ||
1665 | memcpy(de->name, name, namelen); | ||
1666 | } | ||
1617 | /* | 1667 | /* |
1618 | * Add a new entry into a directory (leaf) block. If de is non-NULL, | 1668 | * Add a new entry into a directory (leaf) block. If de is non-NULL, |
1619 | * it points to a directory entry which is guaranteed to be large | 1669 | * it points to a directory entry which is guaranteed to be large |
@@ -1629,12 +1679,10 @@ static int add_dirent_to_buf(handle_t *handle, struct dentry *dentry, | |||
1629 | struct inode *dir = dentry->d_parent->d_inode; | 1679 | struct inode *dir = dentry->d_parent->d_inode; |
1630 | const char *name = dentry->d_name.name; | 1680 | const char *name = dentry->d_name.name; |
1631 | int namelen = dentry->d_name.len; | 1681 | int namelen = dentry->d_name.len; |
1632 | unsigned int offset = 0; | ||
1633 | unsigned int blocksize = dir->i_sb->s_blocksize; | 1682 | unsigned int blocksize = dir->i_sb->s_blocksize; |
1634 | unsigned short reclen; | 1683 | unsigned short reclen; |
1635 | int nlen, rlen, err; | ||
1636 | char *top; | ||
1637 | int csum_size = 0; | 1684 | int csum_size = 0; |
1685 | int err; | ||
1638 | 1686 | ||
1639 | if (EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb, | 1687 | if (EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb, |
1640 | EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) | 1688 | EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) |
@@ -1642,23 +1690,11 @@ static int add_dirent_to_buf(handle_t *handle, struct dentry *dentry, | |||
1642 | 1690 | ||
1643 | reclen = EXT4_DIR_REC_LEN(namelen); | 1691 | reclen = EXT4_DIR_REC_LEN(namelen); |
1644 | if (!de) { | 1692 | if (!de) { |
1645 | de = (struct ext4_dir_entry_2 *)bh->b_data; | 1693 | err = ext4_find_dest_de(dir, inode, |
1646 | top = bh->b_data + (blocksize - csum_size) - reclen; | 1694 | bh, bh->b_data, blocksize - csum_size, |
1647 | while ((char *) de <= top) { | 1695 | name, namelen, &de); |
1648 | if (ext4_check_dir_entry(dir, NULL, de, bh, bh->b_data, | 1696 | if (err) |
1649 | bh->b_size, offset)) | 1697 | return err; |
1650 | return -EIO; | ||
1651 | if (ext4_match(namelen, name, de)) | ||
1652 | return -EEXIST; | ||
1653 | nlen = EXT4_DIR_REC_LEN(de->name_len); | ||
1654 | rlen = ext4_rec_len_from_disk(de->rec_len, blocksize); | ||
1655 | if ((de->inode? rlen - nlen: rlen) >= reclen) | ||
1656 | break; | ||
1657 | de = (struct ext4_dir_entry_2 *)((char *)de + rlen); | ||
1658 | offset += rlen; | ||
1659 | } | ||
1660 | if ((char *) de > top) | ||
1661 | return -ENOSPC; | ||
1662 | } | 1698 | } |
1663 | BUFFER_TRACE(bh, "get_write_access"); | 1699 | BUFFER_TRACE(bh, "get_write_access"); |
1664 | err = ext4_journal_get_write_access(handle, bh); | 1700 | err = ext4_journal_get_write_access(handle, bh); |
@@ -1668,19 +1704,8 @@ static int add_dirent_to_buf(handle_t *handle, struct dentry *dentry, | |||
1668 | } | 1704 | } |
1669 | 1705 | ||
1670 | /* By now the buffer is marked for journaling */ | 1706 | /* By now the buffer is marked for journaling */ |
1671 | nlen = EXT4_DIR_REC_LEN(de->name_len); | 1707 | ext4_insert_dentry(inode, de, blocksize, name, namelen); |
1672 | rlen = ext4_rec_len_from_disk(de->rec_len, blocksize); | 1708 | |
1673 | if (de->inode) { | ||
1674 | struct ext4_dir_entry_2 *de1 = (struct ext4_dir_entry_2 *)((char *)de + nlen); | ||
1675 | de1->rec_len = ext4_rec_len_to_disk(rlen - nlen, blocksize); | ||
1676 | de->rec_len = ext4_rec_len_to_disk(nlen, blocksize); | ||
1677 | de = de1; | ||
1678 | } | ||
1679 | de->file_type = EXT4_FT_UNKNOWN; | ||
1680 | de->inode = cpu_to_le32(inode->i_ino); | ||
1681 | ext4_set_de_type(dir->i_sb, de, inode->i_mode); | ||
1682 | de->name_len = namelen; | ||
1683 | memcpy(de->name, name, namelen); | ||
1684 | /* | 1709 | /* |
1685 | * XXX shouldn't update any times until successful | 1710 | * XXX shouldn't update any times until successful |
1686 | * completion of syscall, but too many callers depend | 1711 | * completion of syscall, but too many callers depend |