aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTao Ma <boyu.mt@taobao.com>2012-12-10 14:05:58 -0500
committerTheodore Ts'o <tytso@mit.edu>2012-12-10 14:05:58 -0500
commit978fef914a2e6b8ad5672d0a39f9201b7aa7c396 (patch)
tree1b86969eeb25b92d1b206d9168bd4bf309537c0c
parent226ba972b0863783ad377f741f6ff0538f31ab00 (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.h15
-rw-r--r--fs/ext4/namei.c105
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);
1971extern void ext4_htree_free_dir_info(struct dir_private_info *p); 1971extern void ext4_htree_free_dir_info(struct dir_private_info *p);
1972extern 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);
1977void ext4_insert_dentry(struct inode *inode,
1978 struct ext4_dir_entry_2 *de,
1979 int buf_size,
1980 const char *name, int namelen);
1981static 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 */
1974extern int ext4_sync_file(struct file *, loff_t, loff_t, int); 1989extern 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
1087static 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
1610int 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
1644void 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