diff options
author | Artem Blagodarenko <artem.blagodarenko@gmail.com> | 2017-06-21 21:09:57 -0400 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2017-06-21 21:09:57 -0400 |
commit | e08ac99fa2a25626f573cfa377ef3ddedf2cfe8f (patch) | |
tree | f8d44249cdc7a8405a7a73344a7dc45b5a2455c3 /fs/ext4 | |
parent | 67a7d5f561f469ad2fa5154d2888258ab8e6df7c (diff) |
ext4: add largedir feature
This INCOMPAT_LARGEDIR feature allows larger directories to be created
in ldiskfs, both with directory sizes over 2GB and and a maximum htree
depth of 3 instead of the current limit of 2. These features are needed
in order to exceed the current limit of approximately 10M entries in a
single directory.
This patch was originally written by Yang Sheng to support the Lustre server.
[ Bumped the credits needed to update an indexed directory -- tytso ]
Signed-off-by: Liang Zhen <liang.zhen@intel.com>
Signed-off-by: Yang Sheng <yang.sheng@intel.com>
Signed-off-by: Artem Blagodarenko <artem.blagodarenko@seagate.com>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Reviewed-by: Andreas Dilger <andreas.dilger@intel.com>
Diffstat (limited to 'fs/ext4')
-rw-r--r-- | fs/ext4/ext4.h | 23 | ||||
-rw-r--r-- | fs/ext4/ext4_jbd2.h | 9 | ||||
-rw-r--r-- | fs/ext4/inode.c | 4 | ||||
-rw-r--r-- | fs/ext4/namei.c | 124 |
4 files changed, 113 insertions, 47 deletions
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index 32191548abed..f17a4e7075be 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h | |||
@@ -1800,7 +1800,8 @@ EXT4_FEATURE_INCOMPAT_FUNCS(encrypt, ENCRYPT) | |||
1800 | EXT4_FEATURE_INCOMPAT_MMP | \ | 1800 | EXT4_FEATURE_INCOMPAT_MMP | \ |
1801 | EXT4_FEATURE_INCOMPAT_INLINE_DATA | \ | 1801 | EXT4_FEATURE_INCOMPAT_INLINE_DATA | \ |
1802 | EXT4_FEATURE_INCOMPAT_ENCRYPT | \ | 1802 | EXT4_FEATURE_INCOMPAT_ENCRYPT | \ |
1803 | EXT4_FEATURE_INCOMPAT_CSUM_SEED) | 1803 | EXT4_FEATURE_INCOMPAT_CSUM_SEED | \ |
1804 | EXT4_FEATURE_INCOMPAT_LARGEDIR) | ||
1804 | #define EXT4_FEATURE_RO_COMPAT_SUPP (EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER| \ | 1805 | #define EXT4_FEATURE_RO_COMPAT_SUPP (EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER| \ |
1805 | EXT4_FEATURE_RO_COMPAT_LARGE_FILE| \ | 1806 | EXT4_FEATURE_RO_COMPAT_LARGE_FILE| \ |
1806 | EXT4_FEATURE_RO_COMPAT_GDT_CSUM| \ | 1807 | EXT4_FEATURE_RO_COMPAT_GDT_CSUM| \ |
@@ -2126,6 +2127,16 @@ ext4_group_first_block_no(struct super_block *sb, ext4_group_t group_no) | |||
2126 | */ | 2127 | */ |
2127 | #define ERR_BAD_DX_DIR (-(MAX_ERRNO - 1)) | 2128 | #define ERR_BAD_DX_DIR (-(MAX_ERRNO - 1)) |
2128 | 2129 | ||
2130 | /* htree levels for ext4 */ | ||
2131 | #define EXT4_HTREE_LEVEL_COMPAT 2 | ||
2132 | #define EXT4_HTREE_LEVEL 3 | ||
2133 | |||
2134 | static inline int ext4_dir_htree_level(struct super_block *sb) | ||
2135 | { | ||
2136 | return ext4_has_feature_largedir(sb) ? | ||
2137 | EXT4_HTREE_LEVEL : EXT4_HTREE_LEVEL_COMPAT; | ||
2138 | } | ||
2139 | |||
2129 | /* | 2140 | /* |
2130 | * Timeout and state flag for lazy initialization inode thread. | 2141 | * Timeout and state flag for lazy initialization inode thread. |
2131 | */ | 2142 | */ |
@@ -2756,13 +2767,15 @@ static inline void ext4_r_blocks_count_set(struct ext4_super_block *es, | |||
2756 | es->s_r_blocks_count_hi = cpu_to_le32(blk >> 32); | 2767 | es->s_r_blocks_count_hi = cpu_to_le32(blk >> 32); |
2757 | } | 2768 | } |
2758 | 2769 | ||
2759 | static inline loff_t ext4_isize(struct ext4_inode *raw_inode) | 2770 | static inline loff_t ext4_isize(struct super_block *sb, |
2771 | struct ext4_inode *raw_inode) | ||
2760 | { | 2772 | { |
2761 | if (S_ISREG(le16_to_cpu(raw_inode->i_mode))) | 2773 | if (ext4_has_feature_largedir(sb) || |
2774 | S_ISREG(le16_to_cpu(raw_inode->i_mode))) | ||
2762 | return ((loff_t)le32_to_cpu(raw_inode->i_size_high) << 32) | | 2775 | return ((loff_t)le32_to_cpu(raw_inode->i_size_high) << 32) | |
2763 | le32_to_cpu(raw_inode->i_size_lo); | 2776 | le32_to_cpu(raw_inode->i_size_lo); |
2764 | else | 2777 | |
2765 | return (loff_t) le32_to_cpu(raw_inode->i_size_lo); | 2778 | return (loff_t) le32_to_cpu(raw_inode->i_size_lo); |
2766 | } | 2779 | } |
2767 | 2780 | ||
2768 | static inline void ext4_isize_set(struct ext4_inode *raw_inode, loff_t i_size) | 2781 | static inline void ext4_isize_set(struct ext4_inode *raw_inode, loff_t i_size) |
diff --git a/fs/ext4/ext4_jbd2.h b/fs/ext4/ext4_jbd2.h index f97611171023..5e61e464d71c 100644 --- a/fs/ext4/ext4_jbd2.h +++ b/fs/ext4/ext4_jbd2.h | |||
@@ -77,7 +77,14 @@ | |||
77 | 77 | ||
78 | #define EXT4_RESERVE_TRANS_BLOCKS 12U | 78 | #define EXT4_RESERVE_TRANS_BLOCKS 12U |
79 | 79 | ||
80 | #define EXT4_INDEX_EXTRA_TRANS_BLOCKS 8 | 80 | /* |
81 | * Number of credits needed if we need to insert an entry into a | ||
82 | * directory. For each new index block, we need 4 blocks (old index | ||
83 | * block, new index block, bitmap block, bg summary). For normal | ||
84 | * htree directories there are 2 levels; if the largedir feature | ||
85 | * enabled it's 3 levels. | ||
86 | */ | ||
87 | #define EXT4_INDEX_EXTRA_TRANS_BLOCKS 12U | ||
81 | 88 | ||
82 | #ifdef CONFIG_QUOTA | 89 | #ifdef CONFIG_QUOTA |
83 | /* Amount of blocks needed for quota update - we know that the structure was | 90 | /* Amount of blocks needed for quota update - we know that the structure was |
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 5cf82d03968c..47604d1352fc 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c | |||
@@ -4712,7 +4712,7 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino) | |||
4712 | if (ext4_has_feature_64bit(sb)) | 4712 | if (ext4_has_feature_64bit(sb)) |
4713 | ei->i_file_acl |= | 4713 | ei->i_file_acl |= |
4714 | ((__u64)le16_to_cpu(raw_inode->i_file_acl_high)) << 32; | 4714 | ((__u64)le16_to_cpu(raw_inode->i_file_acl_high)) << 32; |
4715 | inode->i_size = ext4_isize(raw_inode); | 4715 | inode->i_size = ext4_isize(sb, raw_inode); |
4716 | if ((size = i_size_read(inode)) < 0) { | 4716 | if ((size = i_size_read(inode)) < 0) { |
4717 | EXT4_ERROR_INODE(inode, "bad i_size value: %lld", size); | 4717 | EXT4_ERROR_INODE(inode, "bad i_size value: %lld", size); |
4718 | ret = -EFSCORRUPTED; | 4718 | ret = -EFSCORRUPTED; |
@@ -5037,7 +5037,7 @@ static int ext4_do_update_inode(handle_t *handle, | |||
5037 | raw_inode->i_file_acl_high = | 5037 | raw_inode->i_file_acl_high = |
5038 | cpu_to_le16(ei->i_file_acl >> 32); | 5038 | cpu_to_le16(ei->i_file_acl >> 32); |
5039 | raw_inode->i_file_acl_lo = cpu_to_le32(ei->i_file_acl); | 5039 | raw_inode->i_file_acl_lo = cpu_to_le32(ei->i_file_acl); |
5040 | if (ei->i_disksize != ext4_isize(raw_inode)) { | 5040 | if (ei->i_disksize != ext4_isize(inode->i_sb, raw_inode)) { |
5041 | ext4_isize_set(raw_inode, ei->i_disksize); | 5041 | ext4_isize_set(raw_inode, ei->i_disksize); |
5042 | need_datasync = 1; | 5042 | need_datasync = 1; |
5043 | } | 5043 | } |
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index 404256caf9cf..423e1f761768 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c | |||
@@ -513,7 +513,7 @@ ext4_next_entry(struct ext4_dir_entry_2 *p, unsigned long blocksize) | |||
513 | 513 | ||
514 | static inline ext4_lblk_t dx_get_block(struct dx_entry *entry) | 514 | static inline ext4_lblk_t dx_get_block(struct dx_entry *entry) |
515 | { | 515 | { |
516 | return le32_to_cpu(entry->block) & 0x00ffffff; | 516 | return le32_to_cpu(entry->block) & 0x0fffffff; |
517 | } | 517 | } |
518 | 518 | ||
519 | static inline void dx_set_block(struct dx_entry *entry, ext4_lblk_t value) | 519 | static inline void dx_set_block(struct dx_entry *entry, ext4_lblk_t value) |
@@ -739,6 +739,7 @@ dx_probe(struct ext4_filename *fname, struct inode *dir, | |||
739 | struct dx_frame *ret_err = ERR_PTR(ERR_BAD_DX_DIR); | 739 | struct dx_frame *ret_err = ERR_PTR(ERR_BAD_DX_DIR); |
740 | u32 hash; | 740 | u32 hash; |
741 | 741 | ||
742 | memset(frame_in, 0, EXT4_HTREE_LEVEL * sizeof(frame_in[0])); | ||
742 | frame->bh = ext4_read_dirblock(dir, 0, INDEX); | 743 | frame->bh = ext4_read_dirblock(dir, 0, INDEX); |
743 | if (IS_ERR(frame->bh)) | 744 | if (IS_ERR(frame->bh)) |
744 | return (struct dx_frame *) frame->bh; | 745 | return (struct dx_frame *) frame->bh; |
@@ -768,9 +769,15 @@ dx_probe(struct ext4_filename *fname, struct inode *dir, | |||
768 | } | 769 | } |
769 | 770 | ||
770 | indirect = root->info.indirect_levels; | 771 | indirect = root->info.indirect_levels; |
771 | if (indirect > 1) { | 772 | if (indirect >= ext4_dir_htree_level(dir->i_sb)) { |
772 | ext4_warning_inode(dir, "Unimplemented hash depth: %#06x", | 773 | ext4_warning(dir->i_sb, |
773 | root->info.indirect_levels); | 774 | "Directory (ino: %lu) htree depth %#06x exceed" |
775 | "supported value", dir->i_ino, | ||
776 | ext4_dir_htree_level(dir->i_sb)); | ||
777 | if (ext4_dir_htree_level(dir->i_sb) < EXT4_HTREE_LEVEL) { | ||
778 | ext4_warning(dir->i_sb, "Enable large directory " | ||
779 | "feature to access it"); | ||
780 | } | ||
774 | goto fail; | 781 | goto fail; |
775 | } | 782 | } |
776 | 783 | ||
@@ -859,12 +866,19 @@ fail: | |||
859 | 866 | ||
860 | static void dx_release(struct dx_frame *frames) | 867 | static void dx_release(struct dx_frame *frames) |
861 | { | 868 | { |
869 | struct dx_root_info *info; | ||
870 | int i; | ||
871 | |||
862 | if (frames[0].bh == NULL) | 872 | if (frames[0].bh == NULL) |
863 | return; | 873 | return; |
864 | 874 | ||
865 | if (((struct dx_root *)frames[0].bh->b_data)->info.indirect_levels) | 875 | info = &((struct dx_root *)frames[0].bh->b_data)->info; |
866 | brelse(frames[1].bh); | 876 | for (i = 0; i <= info->indirect_levels; i++) { |
867 | brelse(frames[0].bh); | 877 | if (frames[i].bh == NULL) |
878 | break; | ||
879 | brelse(frames[i].bh); | ||
880 | frames[i].bh = NULL; | ||
881 | } | ||
868 | } | 882 | } |
869 | 883 | ||
870 | /* | 884 | /* |
@@ -1050,7 +1064,7 @@ int ext4_htree_fill_tree(struct file *dir_file, __u32 start_hash, | |||
1050 | { | 1064 | { |
1051 | struct dx_hash_info hinfo; | 1065 | struct dx_hash_info hinfo; |
1052 | struct ext4_dir_entry_2 *de; | 1066 | struct ext4_dir_entry_2 *de; |
1053 | struct dx_frame frames[2], *frame; | 1067 | struct dx_frame frames[EXT4_HTREE_LEVEL], *frame; |
1054 | struct inode *dir; | 1068 | struct inode *dir; |
1055 | ext4_lblk_t block; | 1069 | ext4_lblk_t block; |
1056 | int count = 0; | 1070 | int count = 0; |
@@ -1485,7 +1499,7 @@ static struct buffer_head * ext4_dx_find_entry(struct inode *dir, | |||
1485 | struct ext4_dir_entry_2 **res_dir) | 1499 | struct ext4_dir_entry_2 **res_dir) |
1486 | { | 1500 | { |
1487 | struct super_block * sb = dir->i_sb; | 1501 | struct super_block * sb = dir->i_sb; |
1488 | struct dx_frame frames[2], *frame; | 1502 | struct dx_frame frames[EXT4_HTREE_LEVEL], *frame; |
1489 | struct buffer_head *bh; | 1503 | struct buffer_head *bh; |
1490 | ext4_lblk_t block; | 1504 | ext4_lblk_t block; |
1491 | int retval; | 1505 | int retval; |
@@ -1889,7 +1903,7 @@ static int add_dirent_to_buf(handle_t *handle, struct ext4_filename *fname, | |||
1889 | */ | 1903 | */ |
1890 | dir->i_mtime = dir->i_ctime = current_time(dir); | 1904 | dir->i_mtime = dir->i_ctime = current_time(dir); |
1891 | ext4_update_dx_flag(dir); | 1905 | ext4_update_dx_flag(dir); |
1892 | dir->i_version++; | 1906 | inode_inc_iversion(dir); |
1893 | ext4_mark_inode_dirty(handle, dir); | 1907 | ext4_mark_inode_dirty(handle, dir); |
1894 | BUFFER_TRACE(bh, "call ext4_handle_dirty_metadata"); | 1908 | BUFFER_TRACE(bh, "call ext4_handle_dirty_metadata"); |
1895 | err = ext4_handle_dirty_dirent_node(handle, dir, bh); | 1909 | err = ext4_handle_dirty_dirent_node(handle, dir, bh); |
@@ -1908,7 +1922,7 @@ static int make_indexed_dir(handle_t *handle, struct ext4_filename *fname, | |||
1908 | { | 1922 | { |
1909 | struct buffer_head *bh2; | 1923 | struct buffer_head *bh2; |
1910 | struct dx_root *root; | 1924 | struct dx_root *root; |
1911 | struct dx_frame frames[2], *frame; | 1925 | struct dx_frame frames[EXT4_HTREE_LEVEL], *frame; |
1912 | struct dx_entry *entries; | 1926 | struct dx_entry *entries; |
1913 | struct ext4_dir_entry_2 *de, *de2; | 1927 | struct ext4_dir_entry_2 *de, *de2; |
1914 | struct ext4_dir_entry_tail *t; | 1928 | struct ext4_dir_entry_tail *t; |
@@ -2127,13 +2141,16 @@ out: | |||
2127 | static int ext4_dx_add_entry(handle_t *handle, struct ext4_filename *fname, | 2141 | static int ext4_dx_add_entry(handle_t *handle, struct ext4_filename *fname, |
2128 | struct inode *dir, struct inode *inode) | 2142 | struct inode *dir, struct inode *inode) |
2129 | { | 2143 | { |
2130 | struct dx_frame frames[2], *frame; | 2144 | struct dx_frame frames[EXT4_HTREE_LEVEL], *frame; |
2131 | struct dx_entry *entries, *at; | 2145 | struct dx_entry *entries, *at; |
2132 | struct buffer_head *bh; | 2146 | struct buffer_head *bh; |
2133 | struct super_block *sb = dir->i_sb; | 2147 | struct super_block *sb = dir->i_sb; |
2134 | struct ext4_dir_entry_2 *de; | 2148 | struct ext4_dir_entry_2 *de; |
2149 | int restart; | ||
2135 | int err; | 2150 | int err; |
2136 | 2151 | ||
2152 | again: | ||
2153 | restart = 0; | ||
2137 | frame = dx_probe(fname, dir, NULL, frames); | 2154 | frame = dx_probe(fname, dir, NULL, frames); |
2138 | if (IS_ERR(frame)) | 2155 | if (IS_ERR(frame)) |
2139 | return PTR_ERR(frame); | 2156 | return PTR_ERR(frame); |
@@ -2155,24 +2172,44 @@ static int ext4_dx_add_entry(handle_t *handle, struct ext4_filename *fname, | |||
2155 | if (err != -ENOSPC) | 2172 | if (err != -ENOSPC) |
2156 | goto cleanup; | 2173 | goto cleanup; |
2157 | 2174 | ||
2175 | err = 0; | ||
2158 | /* Block full, should compress but for now just split */ | 2176 | /* Block full, should compress but for now just split */ |
2159 | dxtrace(printk(KERN_DEBUG "using %u of %u node entries\n", | 2177 | dxtrace(printk(KERN_DEBUG "using %u of %u node entries\n", |
2160 | dx_get_count(entries), dx_get_limit(entries))); | 2178 | dx_get_count(entries), dx_get_limit(entries))); |
2161 | /* Need to split index? */ | 2179 | /* Need to split index? */ |
2162 | if (dx_get_count(entries) == dx_get_limit(entries)) { | 2180 | if (dx_get_count(entries) == dx_get_limit(entries)) { |
2163 | ext4_lblk_t newblock; | 2181 | ext4_lblk_t newblock; |
2164 | unsigned icount = dx_get_count(entries); | 2182 | int levels = frame - frames + 1; |
2165 | int levels = frame - frames; | 2183 | unsigned int icount; |
2184 | int add_level = 1; | ||
2166 | struct dx_entry *entries2; | 2185 | struct dx_entry *entries2; |
2167 | struct dx_node *node2; | 2186 | struct dx_node *node2; |
2168 | struct buffer_head *bh2; | 2187 | struct buffer_head *bh2; |
2169 | 2188 | ||
2170 | if (levels && (dx_get_count(frames->entries) == | 2189 | while (frame > frames) { |
2171 | dx_get_limit(frames->entries))) { | 2190 | if (dx_get_count((frame - 1)->entries) < |
2172 | ext4_warning_inode(dir, "Directory index full!"); | 2191 | dx_get_limit((frame - 1)->entries)) { |
2192 | add_level = 0; | ||
2193 | break; | ||
2194 | } | ||
2195 | frame--; /* split higher index block */ | ||
2196 | at = frame->at; | ||
2197 | entries = frame->entries; | ||
2198 | restart = 1; | ||
2199 | } | ||
2200 | if (add_level && levels == ext4_dir_htree_level(sb)) { | ||
2201 | ext4_warning(sb, "Directory (ino: %lu) index full, " | ||
2202 | "reach max htree level :%d", | ||
2203 | dir->i_ino, levels); | ||
2204 | if (ext4_dir_htree_level(sb) < EXT4_HTREE_LEVEL) { | ||
2205 | ext4_warning(sb, "Large directory feature is " | ||
2206 | "not enabled on this " | ||
2207 | "filesystem"); | ||
2208 | } | ||
2173 | err = -ENOSPC; | 2209 | err = -ENOSPC; |
2174 | goto cleanup; | 2210 | goto cleanup; |
2175 | } | 2211 | } |
2212 | icount = dx_get_count(entries); | ||
2176 | bh2 = ext4_append(handle, dir, &newblock); | 2213 | bh2 = ext4_append(handle, dir, &newblock); |
2177 | if (IS_ERR(bh2)) { | 2214 | if (IS_ERR(bh2)) { |
2178 | err = PTR_ERR(bh2); | 2215 | err = PTR_ERR(bh2); |
@@ -2187,7 +2224,7 @@ static int ext4_dx_add_entry(handle_t *handle, struct ext4_filename *fname, | |||
2187 | err = ext4_journal_get_write_access(handle, frame->bh); | 2224 | err = ext4_journal_get_write_access(handle, frame->bh); |
2188 | if (err) | 2225 | if (err) |
2189 | goto journal_error; | 2226 | goto journal_error; |
2190 | if (levels) { | 2227 | if (!add_level) { |
2191 | unsigned icount1 = icount/2, icount2 = icount - icount1; | 2228 | unsigned icount1 = icount/2, icount2 = icount - icount1; |
2192 | unsigned hash2 = dx_get_hash(entries + icount1); | 2229 | unsigned hash2 = dx_get_hash(entries + icount1); |
2193 | dxtrace(printk(KERN_DEBUG "Split index %i/%i\n", | 2230 | dxtrace(printk(KERN_DEBUG "Split index %i/%i\n", |
@@ -2195,7 +2232,7 @@ static int ext4_dx_add_entry(handle_t *handle, struct ext4_filename *fname, | |||
2195 | 2232 | ||
2196 | BUFFER_TRACE(frame->bh, "get_write_access"); /* index root */ | 2233 | BUFFER_TRACE(frame->bh, "get_write_access"); /* index root */ |
2197 | err = ext4_journal_get_write_access(handle, | 2234 | err = ext4_journal_get_write_access(handle, |
2198 | frames[0].bh); | 2235 | (frame - 1)->bh); |
2199 | if (err) | 2236 | if (err) |
2200 | goto journal_error; | 2237 | goto journal_error; |
2201 | 2238 | ||
@@ -2211,17 +2248,25 @@ static int ext4_dx_add_entry(handle_t *handle, struct ext4_filename *fname, | |||
2211 | frame->entries = entries = entries2; | 2248 | frame->entries = entries = entries2; |
2212 | swap(frame->bh, bh2); | 2249 | swap(frame->bh, bh2); |
2213 | } | 2250 | } |
2214 | dx_insert_block(frames + 0, hash2, newblock); | 2251 | dx_insert_block((frame - 1), hash2, newblock); |
2215 | dxtrace(dx_show_index("node", frames[1].entries)); | 2252 | dxtrace(dx_show_index("node", frame->entries)); |
2216 | dxtrace(dx_show_index("node", | 2253 | dxtrace(dx_show_index("node", |
2217 | ((struct dx_node *) bh2->b_data)->entries)); | 2254 | ((struct dx_node *) bh2->b_data)->entries)); |
2218 | err = ext4_handle_dirty_dx_node(handle, dir, bh2); | 2255 | err = ext4_handle_dirty_dx_node(handle, dir, bh2); |
2219 | if (err) | 2256 | if (err) |
2220 | goto journal_error; | 2257 | goto journal_error; |
2221 | brelse (bh2); | 2258 | brelse (bh2); |
2259 | err = ext4_handle_dirty_dx_node(handle, dir, | ||
2260 | (frame - 1)->bh); | ||
2261 | if (err) | ||
2262 | goto journal_error; | ||
2263 | if (restart) { | ||
2264 | err = ext4_handle_dirty_dx_node(handle, dir, | ||
2265 | frame->bh); | ||
2266 | goto journal_error; | ||
2267 | } | ||
2222 | } else { | 2268 | } else { |
2223 | dxtrace(printk(KERN_DEBUG | 2269 | struct dx_root *dxroot; |
2224 | "Creating second level index...\n")); | ||
2225 | memcpy((char *) entries2, (char *) entries, | 2270 | memcpy((char *) entries2, (char *) entries, |
2226 | icount * sizeof(struct dx_entry)); | 2271 | icount * sizeof(struct dx_entry)); |
2227 | dx_set_limit(entries2, dx_node_limit(dir)); | 2272 | dx_set_limit(entries2, dx_node_limit(dir)); |
@@ -2229,22 +2274,18 @@ static int ext4_dx_add_entry(handle_t *handle, struct ext4_filename *fname, | |||
2229 | /* Set up root */ | 2274 | /* Set up root */ |
2230 | dx_set_count(entries, 1); | 2275 | dx_set_count(entries, 1); |
2231 | dx_set_block(entries + 0, newblock); | 2276 | dx_set_block(entries + 0, newblock); |
2232 | ((struct dx_root *) frames[0].bh->b_data)->info.indirect_levels = 1; | 2277 | dxroot = (struct dx_root *)frames[0].bh->b_data; |
2233 | 2278 | dxroot->info.indirect_levels += 1; | |
2234 | /* Add new access path frame */ | 2279 | dxtrace(printk(KERN_DEBUG |
2235 | frame = frames + 1; | 2280 | "Creating %d level index...\n", |
2236 | frame->at = at = at - entries + entries2; | 2281 | info->indirect_levels)); |
2237 | frame->entries = entries = entries2; | 2282 | err = ext4_handle_dirty_dx_node(handle, dir, frame->bh); |
2238 | frame->bh = bh2; | ||
2239 | err = ext4_journal_get_write_access(handle, | ||
2240 | frame->bh); | ||
2241 | if (err) | 2283 | if (err) |
2242 | goto journal_error; | 2284 | goto journal_error; |
2243 | } | 2285 | err = ext4_handle_dirty_dx_node(handle, dir, bh2); |
2244 | err = ext4_handle_dirty_dx_node(handle, dir, frames[0].bh); | 2286 | brelse(bh2); |
2245 | if (err) { | 2287 | restart = 1; |
2246 | ext4_std_error(inode->i_sb, err); | 2288 | goto journal_error; |
2247 | goto cleanup; | ||
2248 | } | 2289 | } |
2249 | } | 2290 | } |
2250 | de = do_split(handle, dir, &bh, frame, &fname->hinfo); | 2291 | de = do_split(handle, dir, &bh, frame, &fname->hinfo); |
@@ -2256,10 +2297,15 @@ static int ext4_dx_add_entry(handle_t *handle, struct ext4_filename *fname, | |||
2256 | goto cleanup; | 2297 | goto cleanup; |
2257 | 2298 | ||
2258 | journal_error: | 2299 | journal_error: |
2259 | ext4_std_error(dir->i_sb, err); | 2300 | ext4_std_error(dir->i_sb, err); /* this is a no-op if err == 0 */ |
2260 | cleanup: | 2301 | cleanup: |
2261 | brelse(bh); | 2302 | brelse(bh); |
2262 | dx_release(frames); | 2303 | dx_release(frames); |
2304 | /* @restart is true means htree-path has been changed, we need to | ||
2305 | * repeat dx_probe() to find out valid htree-path | ||
2306 | */ | ||
2307 | if (restart && err == 0) | ||
2308 | goto again; | ||
2263 | return err; | 2309 | return err; |
2264 | } | 2310 | } |
2265 | 2311 | ||
@@ -2296,7 +2342,7 @@ int ext4_generic_delete_entry(handle_t *handle, | |||
2296 | blocksize); | 2342 | blocksize); |
2297 | else | 2343 | else |
2298 | de->inode = 0; | 2344 | de->inode = 0; |
2299 | dir->i_version++; | 2345 | inode_inc_iversion(dir); |
2300 | return 0; | 2346 | return 0; |
2301 | } | 2347 | } |
2302 | i += ext4_rec_len_from_disk(de->rec_len, blocksize); | 2348 | i += ext4_rec_len_from_disk(de->rec_len, blocksize); |