ext4_journal: forcibly flush data to disk when stop journalling.
[lwext4.git] / lwext4 / ext4_dir_idx.c
1 /*
2  * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * - Redistributions of source code must retain the above copyright
10  *   notice, this list of conditions and the following disclaimer.
11  * - Redistributions in binary form must reproduce the above copyright
12  *   notice, this list of conditions and the following disclaimer in the
13  *   documentation and/or other materials provided with the distribution.
14  * - The name of the author may not be used to endorse or promote products
15  *   derived from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 /** @addtogroup lwext4
30  * @{
31  */
32 /**
33  * @file  ext4_dir_idx.c
34  * @brief Directory indexing procedures.
35  */
36
37 #include "ext4_config.h"
38 #include "ext4_dir_idx.h"
39 #include "ext4_dir.h"
40 #include "ext4_blockdev.h"
41 #include "ext4_fs.h"
42 #include "ext4_super.h"
43 #include "ext4_inode.h"
44 #include "ext4_crc32c.h"
45 #include "ext4_hash.h"
46
47 #include <string.h>
48 #include <stdlib.h>
49
50 /**@brief Get hash version used in directory index.
51  * @param root_info Pointer to root info structure of index
52  * @return Hash algorithm version
53  */
54 static inline uint8_t
55 ext4_dir_dx_rinfo_get_hash_version(struct ext4_dir_idx_rinfo *ri)
56 {
57         return ri->hash_version;
58 }
59
60 /**@brief Set hash version, that will be used in directory index.
61  * @param root_info Pointer to root info structure of index
62  * @param v Hash algorithm version
63  */
64 static inline void
65 ext4_dir_dx_rinfo_set_hash_version(struct ext4_dir_idx_rinfo *ri, uint8_t v)
66 {
67         ri->hash_version = v;
68 }
69
70 /**@brief Get length of root_info structure in bytes.
71  * @param root_info Pointer to root info structure of index
72  * @return Length of the structure
73  */
74 static inline uint8_t
75 ext4_dir_dx_rinfo_get_info_length(struct ext4_dir_idx_rinfo *ri)
76 {
77         return ri->info_length;
78 }
79
80 /**@brief Set length of root_info structure in bytes.
81  * @param root_info   Pointer to root info structure of index
82  * @param info_length Length of the structure
83  */
84 static inline void
85 ext4_dir_dx_root_info_set_info_length(struct ext4_dir_idx_rinfo *ri,
86                                       uint8_t len)
87 {
88         ri->info_length = len;
89 }
90
91 /**@brief Get number of indirect levels of HTree.
92  * @param root_info Pointer to root info structure of index
93  * @return Height of HTree (actually only 0 or 1)
94  */
95 static inline uint8_t
96 ext4_dir_dx_rinfo_get_indirect_levels(struct ext4_dir_idx_rinfo *ri)
97 {
98         return ri->indirect_levels;
99 }
100
101 /**@brief Set number of indirect levels of HTree.
102  * @param root_info Pointer to root info structure of index
103  * @param lvl Height of HTree (actually only 0 or 1)
104  */
105 static inline void
106 ext4_dir_dx_rinfo_set_indirect_levels(struct ext4_dir_idx_rinfo *ri, uint8_t l)
107 {
108         ri->indirect_levels = l;
109 }
110
111 /**@brief Get maximum number of index node entries.
112  * @param climit Pointer to counlimit structure
113  * @return Maximum of entries in node
114  */
115 static inline uint16_t
116 ext4_dir_dx_climit_get_limit(struct ext4_dir_idx_climit *climit)
117 {
118         return to_le16(climit->limit);
119 }
120
121 /**@brief Set maximum number of index node entries.
122  * @param climit Pointer to counlimit structure
123  * @param limit Maximum of entries in node
124  */
125 static inline void
126 ext4_dir_dx_climit_set_limit(struct ext4_dir_idx_climit *climit, uint16_t limit)
127 {
128         climit->limit = to_le16(limit);
129 }
130
131 /**@brief Get current number of index node entries.
132  * @param climit Pointer to counlimit structure
133  * @return Number of entries in node
134  */
135 static inline uint16_t
136 ext4_dir_dx_climit_get_count(struct ext4_dir_idx_climit *climit)
137 {
138         return to_le16(climit->count);
139 }
140
141 /**@brief Set current number of index node entries.
142  * @param climit Pointer to counlimit structure
143  * @param count Number of entries in node
144  */
145 static inline void
146 ext4_dir_dx_climit_set_count(struct ext4_dir_idx_climit *climit, uint16_t count)
147 {
148         climit->count = to_le16(count);
149 }
150
151 /**@brief Get hash value of index entry.
152  * @param entry Pointer to index entry
153  * @return Hash value
154  */
155 static inline uint32_t
156 ext4_dir_dx_entry_get_hash(struct ext4_dir_idx_entry *entry)
157 {
158         return to_le32(entry->hash);
159 }
160
161 /**@brief Set hash value of index entry.
162  * @param entry Pointer to index entry
163  * @param hash  Hash value
164  */
165 static inline void
166 ext4_dir_dx_entry_set_hash(struct ext4_dir_idx_entry *entry, uint32_t hash)
167 {
168         entry->hash = to_le32(hash);
169 }
170
171 /**@brief Get block address where child node is located.
172  * @param entry Pointer to index entry
173  * @return Block address of child node
174  */
175 static inline uint32_t
176 ext4_dir_dx_entry_get_block(struct ext4_dir_idx_entry *entry)
177 {
178         return to_le32(entry->block);
179 }
180
181 /**@brief Set block address where child node is located.
182  * @param entry Pointer to index entry
183  * @param block Block address of child node
184  */
185 static inline void
186 ext4_dir_dx_entry_set_block(struct ext4_dir_idx_entry *entry, uint32_t block)
187 {
188         entry->block = to_le32(block);
189 }
190
191 /**@brief Sort entry item.*/
192 struct ext4_dx_sort_entry {
193         uint32_t hash;
194         uint32_t rec_len;
195         void *dentry;
196 };
197
198 static int ext4_dir_dx_hash_string(struct ext4_hash_info *hinfo, int len,
199                                    const char *name)
200 {
201         return ext2_htree_hash(name, len, hinfo->seed, hinfo->hash_version,
202                                &hinfo->hash, &hinfo->minor_hash);
203 }
204
205 #if CONFIG_META_CSUM_ENABLE
206 static uint32_t ext4_dir_dx_checksum(struct ext4_inode_ref *inode_ref, void *de,
207                                      int count_offset, int count,
208                                      struct ext4_dir_idx_tail *t)
209 {
210         uint32_t orig_cum, csum = 0;
211         struct ext4_sblock *sb = &inode_ref->fs->sb;
212         int sz;
213
214         /* Compute the checksum only if the filesystem supports it */
215         if (ext4_sb_feature_ro_com(sb, EXT4_FRO_COM_METADATA_CSUM)) {
216                 uint32_t ino_index = to_le32(inode_ref->index);
217                 uint32_t ino_gen;
218                 ino_gen = to_le32(ext4_inode_get_generation(inode_ref->inode));
219
220                 sz = count_offset + (count * sizeof(struct ext4_dir_idx_tail));
221                 orig_cum = t->checksum;
222                 t->checksum = 0;
223                 /* First calculate crc32 checksum against fs uuid */
224                 csum = ext4_crc32c(EXT4_CRC32_INIT, sb->uuid, sizeof(sb->uuid));
225                 /* Then calculate crc32 checksum against inode number
226                  * and inode generation */
227                 csum = ext4_crc32c(csum, &ino_index, sizeof(ino_index));
228                 csum = ext4_crc32c(csum, &ino_gen, sizeof(ino_gen));
229                 /* After that calculate crc32 checksum against all the dx_entry */
230                 csum = ext4_crc32c(csum, de, sz);
231                 /* Finally calculate crc32 checksum for dx_tail */
232                 csum = ext4_crc32c(csum, t, sizeof(struct ext4_dir_idx_tail));
233                 t->checksum = orig_cum;
234         }
235         return csum;
236 }
237
238 static struct ext4_dir_idx_climit *
239 ext4_dir_dx_get_climit(struct ext4_inode_ref *inode_ref,
240                            struct ext4_dir_en *dirent, int *offset)
241 {
242         struct ext4_dir_en *dp;
243         struct ext4_dir_idx_root *root;
244         struct ext4_sblock *sb = &inode_ref->fs->sb;
245         uint32_t block_size = ext4_sb_get_block_size(sb);
246         uint16_t entry_len = ext4_dir_en_get_entry_len(dirent);
247         int count_offset;
248
249
250         if (entry_len == 12) {
251                 root = (struct ext4_dir_idx_root *)dirent;
252                 dp = (struct ext4_dir_en *)&root->dots[1];
253                 if (ext4_dir_en_get_entry_len(dp) != (block_size - 12))
254                         return NULL;
255                 if (root->info.reserved_zero)
256                         return NULL;
257                 if (root->info.info_length != sizeof(struct ext4_dir_idx_rinfo))
258                         return NULL;
259                 count_offset = 32;
260         } else if (entry_len == block_size) {
261                 count_offset = 8;
262         } else {
263                 return NULL;
264         }
265
266         if (offset)
267                 *offset = count_offset;
268         return (struct ext4_dir_idx_climit *)(((char *)dirent) + count_offset);
269 }
270
271 /*
272  * BIG FAT NOTES:
273  *       Currently we do not verify the checksum of HTree node.
274  */
275 static bool ext4_dir_dx_csum_verify(struct ext4_inode_ref *inode_ref,
276                                     struct ext4_dir_en *de)
277 {
278         struct ext4_sblock *sb = &inode_ref->fs->sb;
279         uint32_t block_size = ext4_sb_get_block_size(sb);
280         int coff, limit, cnt;
281
282         if (ext4_sb_feature_ro_com(sb, EXT4_FRO_COM_METADATA_CSUM)) {
283                 struct ext4_dir_idx_climit *climit;
284                 climit = ext4_dir_dx_get_climit(inode_ref, de, &coff);
285                 if (!climit) {
286                         /* Directory seems corrupted. */
287                         return true;
288                 }
289                 struct ext4_dir_idx_tail *t;
290                 limit = ext4_dir_dx_climit_get_limit(climit);
291                 cnt = ext4_dir_dx_climit_get_count(climit);
292                 if (coff + (limit * sizeof(struct ext4_dir_idx_entry)) >
293                     (block_size - sizeof(struct ext4_dir_idx_tail))) {
294                         /* There is no space to hold the checksum */
295                         return true;
296                 }
297                 t = (void *)(((struct ext4_dir_idx_entry *)climit) + limit);
298
299                 uint32_t c;
300                 c = to_le32(ext4_dir_dx_checksum(inode_ref, de, coff, cnt, t));
301                 if (t->checksum != c)
302                         return false;
303         }
304         return true;
305 }
306
307
308 static void ext4_dir_set_dx_csum(struct ext4_inode_ref *inode_ref,
309                                  struct ext4_dir_en *dirent)
310 {
311         int coff, limit, count;
312         struct ext4_sblock *sb = &inode_ref->fs->sb;
313         uint32_t block_size = ext4_sb_get_block_size(sb);
314
315         if (ext4_sb_feature_ro_com(sb, EXT4_FRO_COM_METADATA_CSUM)) {
316                 struct ext4_dir_idx_climit *climit;
317                 climit = ext4_dir_dx_get_climit(inode_ref, dirent, &coff);
318                 if (!climit) {
319                         /* Directory seems corrupted. */
320                         return;
321                 }
322                 struct ext4_dir_idx_tail *t;
323                 limit = ext4_dir_dx_climit_get_limit(climit);
324                 count = ext4_dir_dx_climit_get_count(climit);
325                 if (coff + (limit * sizeof(struct ext4_dir_idx_entry)) >
326                    (block_size - sizeof(struct ext4_dir_idx_tail))) {
327                         /* There is no space to hold the checksum */
328                         return;
329                 }
330
331                 t = (void *)(((struct ext4_dir_idx_entry *)climit) + limit);
332                 t->checksum = to_le32(ext4_dir_dx_checksum(inode_ref, dirent,
333                                         coff, count, t));
334         }
335 }
336 #else
337 #define ext4_dir_dx_csum_verify(...) true
338 #define ext4_dir_set_dx_csum(...)
339 #endif
340
341 /****************************************************************************/
342
343 int ext4_dir_dx_init(struct ext4_inode_ref *dir, struct ext4_inode_ref *parent)
344 {
345         /* Load block 0, where will be index root located */
346         ext4_fsblk_t fblock;
347         uint32_t iblock;
348         struct ext4_sblock *sb = &dir->fs->sb;
349         uint32_t block_size = ext4_sb_get_block_size(&dir->fs->sb);
350
351         int rc = ext4_fs_append_inode_dblk(dir, &fblock, &iblock);
352         if (rc != EOK)
353                 return rc;
354
355         struct ext4_block block;
356         rc = ext4_block_get_noread(dir->fs->bdev, &block, fblock);
357         if (rc != EOK)
358                 return rc;
359
360         /* Initialize pointers to data structures */
361         struct ext4_dir_idx_root *root = (void *)block.data;
362         struct ext4_dir_idx_rinfo *info = &(root->info);
363
364         memset(root, 0, sizeof(struct ext4_dir_idx_root));
365         struct ext4_dir_en *de;
366
367         /* Initialize dot entries */
368         de = (struct ext4_dir_en *)root->dots;
369         ext4_dir_write_entry(sb, de, 12, dir, ".", strlen("."));
370
371         de = (struct ext4_dir_en *)(root->dots + 1);
372         uint16_t elen = block_size - 12;
373         ext4_dir_write_entry(sb, de, elen, parent, "..", strlen(".."));
374
375         /* Initialize root info structure */
376         uint8_t hash_version = ext4_get8(&dir->fs->sb, default_hash_version);
377
378         ext4_dir_dx_rinfo_set_hash_version(info, hash_version);
379         ext4_dir_dx_rinfo_set_indirect_levels(info, 0);
380         ext4_dir_dx_root_info_set_info_length(info, 8);
381
382         /* Set limit and current number of entries */
383         struct ext4_dir_idx_climit *climit;
384         climit = (struct ext4_dir_idx_climit *)&root->en;
385
386         ext4_dir_dx_climit_set_count(climit, 1);
387
388         uint32_t entry_space;
389         entry_space = block_size - 2 * sizeof(struct ext4_dir_idx_dot_en) -
390                         sizeof(struct ext4_dir_idx_rinfo);
391
392         if (ext4_sb_feature_ro_com(sb, EXT4_FRO_COM_METADATA_CSUM))
393                 entry_space -= sizeof(struct ext4_dir_idx_tail);
394
395         uint16_t root_limit = entry_space / sizeof(struct ext4_dir_idx_entry);
396         ext4_dir_dx_climit_set_limit(climit, root_limit);
397
398         /* Append new block, where will be new entries inserted in the future */
399         rc = ext4_fs_append_inode_dblk(dir, &fblock, &iblock);
400         if (rc != EOK) {
401                 ext4_block_set(dir->fs->bdev, &block);
402                 return rc;
403         }
404
405         struct ext4_block new_block;
406         rc = ext4_block_get_noread(dir->fs->bdev, &new_block, fblock);
407         if (rc != EOK) {
408                 ext4_block_set(dir->fs->bdev, &block);
409                 return rc;
410         }
411
412         /* Fill the whole block with empty entry */
413         struct ext4_dir_en *be = (void *)new_block.data;
414
415         if (ext4_sb_feature_ro_com(sb, EXT4_FRO_COM_METADATA_CSUM)) {
416                 uint16_t len = block_size - sizeof(struct ext4_dir_entry_tail);
417                 ext4_dir_en_set_entry_len(be, len);
418                 ext4_dir_en_set_name_len(sb, be, 0);
419                 ext4_dir_en_set_inode_type(sb, be, EXT4_DE_UNKNOWN);
420                 ext4_dir_init_entry_tail(EXT4_DIRENT_TAIL(be, block_size));
421                 ext4_dir_set_csum(dir, be);
422         } else {
423                 ext4_dir_en_set_entry_len(be, block_size);
424         }
425
426         ext4_dir_en_set_inode(be, 0);
427
428         ext4_bcache_set_dirty(new_block.buf);
429         rc = ext4_block_set(dir->fs->bdev, &new_block);
430         if (rc != EOK) {
431                 ext4_block_set(dir->fs->bdev, &block);
432                 return rc;
433         }
434
435         /* Connect new block to the only entry in index */
436         struct ext4_dir_idx_entry *entry = root->en;
437         ext4_dir_dx_entry_set_block(entry, iblock);
438
439         ext4_dir_set_dx_csum(dir, (struct ext4_dir_en *)block.data);
440         ext4_bcache_set_dirty(block.buf);
441
442         return ext4_block_set(dir->fs->bdev, &block);
443 }
444
445 /**@brief Initialize hash info structure necessary for index operations.
446  * @param hinfo      Pointer to hinfo to be initialized
447  * @param root_block Root block (number 0) of index
448  * @param sb         Pointer to superblock
449  * @param name_len   Length of name to be computed hash value from
450  * @param name       Name to be computed hash value from
451  * @return Standard error code
452  */
453 static int ext4_dir_hinfo_init(struct ext4_hash_info *hinfo,
454                                struct ext4_block *root_block,
455                                struct ext4_sblock *sb, size_t name_len,
456                                const char *name)
457 {
458         struct ext4_dir_idx_root *root;
459
460         root = (struct ext4_dir_idx_root *)root_block->data;
461         if ((root->info.hash_version != EXT2_HTREE_LEGACY) &&
462             (root->info.hash_version != EXT2_HTREE_HALF_MD4) &&
463             (root->info.hash_version != EXT2_HTREE_TEA))
464                 return EXT4_ERR_BAD_DX_DIR;
465
466         /* Check unused flags */
467         if (root->info.unused_flags != 0)
468                 return EXT4_ERR_BAD_DX_DIR;
469
470         /* Check indirect levels */
471         if (root->info.indirect_levels > 1)
472                 return EXT4_ERR_BAD_DX_DIR;
473
474         /* Check if node limit is correct */
475         uint32_t block_size = ext4_sb_get_block_size(sb);
476         uint32_t entry_space = block_size;
477         entry_space -= 2 * sizeof(struct ext4_dir_idx_dot_en);
478         entry_space -= sizeof(struct ext4_dir_idx_rinfo);
479         if (ext4_sb_feature_ro_com(sb, EXT4_FRO_COM_METADATA_CSUM))
480                 entry_space -= sizeof(struct ext4_dir_idx_tail);
481         entry_space = entry_space / sizeof(struct ext4_dir_idx_entry);
482
483         struct ext4_dir_idx_climit *climit = (void *)&root->en;
484         uint16_t limit = ext4_dir_dx_climit_get_limit(climit);
485         if (limit != entry_space)
486                 return EXT4_ERR_BAD_DX_DIR;
487
488         /* Check hash version and modify if necessary */
489         hinfo->hash_version = ext4_dir_dx_rinfo_get_hash_version(&root->info);
490         if ((hinfo->hash_version <= EXT2_HTREE_TEA) &&
491             (ext4_sb_check_flag(sb, EXT4_SUPERBLOCK_FLAGS_UNSIGNED_HASH))) {
492                 /* Use unsigned hash */
493                 hinfo->hash_version += 3;
494         }
495
496         /* Load hash seed from superblock */
497         hinfo->seed = ext4_get8(sb, hash_seed);
498
499         /* Compute hash value of name */
500         if (name)
501                 return ext4_dir_dx_hash_string(hinfo, name_len, name);
502
503         return EOK;
504 }
505
506 /**@brief Walk through index tree and load leaf with corresponding hash value.
507  * @param hinfo      Initialized hash info structure
508  * @param inode_ref  Current i-node
509  * @param root_block Root block (iblock 0), where is root node located
510  * @param dx_block   Pointer to leaf node in dx_blocks array
511  * @param dx_blocks  Array with the whole path from root to leaf
512  * @return Standard error code
513  */
514 static int ext4_dir_dx_get_leaf(struct ext4_hash_info *hinfo,
515                                 struct ext4_inode_ref *inode_ref,
516                                 struct ext4_block *root_block,
517                                 struct ext4_dir_idx_block **dx_block,
518                                 struct ext4_dir_idx_block *dx_blocks)
519 {
520         struct ext4_dir_idx_root *root;
521         struct ext4_dir_idx_entry *entries;
522         struct ext4_dir_idx_entry *p;
523         struct ext4_dir_idx_entry *q;
524         struct ext4_dir_idx_entry *m;
525         struct ext4_dir_idx_entry *at;
526         ext4_fsblk_t fblk;
527         uint32_t block_size;
528         uint16_t limit;
529         uint16_t entry_space;
530         uint8_t ind_level;
531         int r;
532
533         struct ext4_dir_idx_block *tmp_dx_blk = dx_blocks;
534         struct ext4_block *tmp_blk = root_block;
535         struct ext4_sblock *sb = &inode_ref->fs->sb;
536
537         block_size = ext4_sb_get_block_size(sb);
538         root = (struct ext4_dir_idx_root *)root_block->data;
539         entries = (struct ext4_dir_idx_entry *)&root->en;
540         limit = ext4_dir_dx_climit_get_limit((void *)entries);
541         ind_level = ext4_dir_dx_rinfo_get_indirect_levels(&root->info);
542
543         /* Walk through the index tree */
544         while (true) {
545                 uint16_t cnt = ext4_dir_dx_climit_get_count((void *)entries);
546                 if ((cnt == 0) || (cnt > limit))
547                         return EXT4_ERR_BAD_DX_DIR;
548
549                 /* Do binary search in every node */
550                 p = entries + 1;
551                 q = entries + cnt - 1;
552
553                 while (p <= q) {
554                         m = p + (q - p) / 2;
555                         if (ext4_dir_dx_entry_get_hash(m) > hinfo->hash)
556                                 q = m - 1;
557                         else
558                                 p = m + 1;
559                 }
560
561                 at = p - 1;
562
563                 /* Write results */
564                 memcpy(&tmp_dx_blk->b, tmp_blk, sizeof(struct ext4_block));
565                 tmp_dx_blk->entries = entries;
566                 tmp_dx_blk->position = at;
567
568                 /* Is algorithm in the leaf? */
569                 if (ind_level == 0) {
570                         *dx_block = tmp_dx_blk;
571                         return EOK;
572                 }
573
574                 /* Goto child node */
575                 uint32_t n_blk = ext4_dir_dx_entry_get_block(at);
576
577                 ind_level--;
578
579                 r = ext4_fs_get_inode_dblk_idx(inode_ref, n_blk, &fblk, false);
580                 if (r != EOK)
581                         return r;
582
583                 r = ext4_block_get(inode_ref->fs->bdev, tmp_blk, fblk);
584                 if (r != EOK)
585                         return r;
586
587                 entries = ((struct ext4_dir_idx_node *)tmp_blk->data)->entries;
588                 limit = ext4_dir_dx_climit_get_limit((void *)entries);
589
590                 entry_space = block_size - sizeof(struct ext4_fake_dir_entry);
591                 if (ext4_sb_feature_ro_com(sb, EXT4_FRO_COM_METADATA_CSUM))
592                         entry_space -= sizeof(struct ext4_dir_idx_tail);
593
594                 entry_space = entry_space / sizeof(struct ext4_dir_idx_entry);
595
596                 if (limit != entry_space) {
597                         ext4_block_set(inode_ref->fs->bdev, tmp_blk);
598                         return EXT4_ERR_BAD_DX_DIR;
599                 }
600
601                 if (!ext4_dir_dx_csum_verify(inode_ref, (void *)tmp_blk->data)) {
602                         ext4_dbg(DEBUG_DIR_IDX,
603                                         DBG_WARN "HTree checksum failed."
604                                         "Inode: %" PRIu32", "
605                                         "Block: %" PRIu32"\n",
606                                         inode_ref->index,
607                                         n_blk);
608                 }
609
610                 ++tmp_dx_blk;
611         }
612
613         /* Unreachable */
614         return EOK;
615 }
616
617 /**@brief Check if the the next block would be checked during entry search.
618  * @param inode_ref Directory i-node
619  * @param hash      Hash value to check
620  * @param dx_block  Current block
621  * @param dx_blocks Array with path from root to leaf node
622  * @return Standard Error code
623  */
624 static int ext4_dir_dx_next_block(struct ext4_inode_ref *inode_ref,
625                                   uint32_t hash,
626                                   struct ext4_dir_idx_block *dx_block,
627                                   struct ext4_dir_idx_block *dx_blocks)
628 {
629         int r;
630         uint32_t num_handles = 0;
631         ext4_fsblk_t blk_adr;
632         struct ext4_dir_idx_block *p = dx_block;
633
634         /* Try to find data block with next bunch of entries */
635         while (true) {
636                 uint16_t cnt = ext4_dir_dx_climit_get_count((void *)p->entries);
637
638                 p->position++;
639                 if (p->position < p->entries + cnt)
640                         break;
641
642                 if (p == dx_blocks)
643                         return EOK;
644
645                 num_handles++;
646                 p--;
647         }
648
649         /* Check hash collision (if not occurred - no next block cannot be
650          * used)*/
651         uint32_t current_hash = ext4_dir_dx_entry_get_hash(p->position);
652         if ((hash & 1) == 0) {
653                 if ((current_hash & ~1) != hash)
654                         return 0;
655         }
656
657         /* Fill new path */
658         while (num_handles--) {
659                 uint32_t blk = ext4_dir_dx_entry_get_block(p->position);
660                 r = ext4_fs_get_inode_dblk_idx(inode_ref, blk, &blk_adr, false);
661                 if (r != EOK)
662                         return r;
663
664                 struct ext4_block b;
665                 r = ext4_block_get(inode_ref->fs->bdev, &b, blk_adr);
666                 if (r != EOK)
667                         return r;
668
669                 if (!ext4_dir_dx_csum_verify(inode_ref, (void *)b.data)) {
670                         ext4_dbg(DEBUG_DIR_IDX,
671                                         DBG_WARN "HTree checksum failed."
672                                         "Inode: %" PRIu32", "
673                                         "Block: %" PRIu32"\n",
674                                         inode_ref->index,
675                                         blk);
676                 }
677
678                 p++;
679
680                 /* Don't forget to put old block (prevent memory leak) */
681                 r = ext4_block_set(inode_ref->fs->bdev, &p->b);
682                 if (r != EOK)
683                         return r;
684
685                 memcpy(&p->b, &b, sizeof(b));
686                 p->entries = ((struct ext4_dir_idx_node *)b.data)->entries;
687                 p->position = p->entries;
688         }
689
690         return ENOENT;
691 }
692
693 int ext4_dir_dx_find_entry(struct ext4_dir_search_result *result,
694                            struct ext4_inode_ref *inode_ref, size_t name_len,
695                            const char *name)
696 {
697         /* Load direct block 0 (index root) */
698         ext4_fsblk_t root_block_addr;
699         int rc2;
700         int rc;
701         rc = ext4_fs_get_inode_dblk_idx(inode_ref,  0, &root_block_addr, false);
702         if (rc != EOK)
703                 return rc;
704
705         struct ext4_fs *fs = inode_ref->fs;
706
707         struct ext4_block root_block;
708         rc = ext4_block_get(fs->bdev, &root_block, root_block_addr);
709         if (rc != EOK)
710                 return rc;
711
712         if (!ext4_dir_dx_csum_verify(inode_ref, (void *)root_block.data)) {
713                 ext4_dbg(DEBUG_DIR_IDX,
714                          DBG_WARN "HTree root checksum failed."
715                          "Inode: %" PRIu32", "
716                          "Block: %" PRIu32"\n",
717                          inode_ref->index,
718                          (uint32_t)0);
719         }
720
721         /* Initialize hash info (compute hash value) */
722         struct ext4_hash_info hinfo;
723         rc = ext4_dir_hinfo_init(&hinfo, &root_block, &fs->sb, name_len, name);
724         if (rc != EOK) {
725                 ext4_block_set(fs->bdev, &root_block);
726                 return EXT4_ERR_BAD_DX_DIR;
727         }
728
729         /*
730          * Hardcoded number 2 means maximum height of index tree,
731          * specified in the Linux driver.
732          */
733         struct ext4_dir_idx_block dx_blocks[2];
734         struct ext4_dir_idx_block *dx_block;
735         struct ext4_dir_idx_block *tmp;
736
737         rc = ext4_dir_dx_get_leaf(&hinfo, inode_ref, &root_block, &dx_block,
738                                   dx_blocks);
739         if (rc != EOK) {
740                 ext4_block_set(fs->bdev, &root_block);
741                 return EXT4_ERR_BAD_DX_DIR;
742         }
743
744         do {
745                 /* Load leaf block */
746                 uint32_t leaf_blk_idx;
747                 ext4_fsblk_t leaf_block_addr;
748                 struct ext4_block b;
749
750                 leaf_blk_idx = ext4_dir_dx_entry_get_block(dx_block->position);
751                 rc = ext4_fs_get_inode_dblk_idx(inode_ref, leaf_blk_idx,
752                                                 &leaf_block_addr, false);
753                 if (rc != EOK)
754                         goto cleanup;
755
756                 rc = ext4_block_get(fs->bdev, &b, leaf_block_addr);
757                 if (rc != EOK)
758                         goto cleanup;
759
760                 if (!ext4_dir_csum_verify(inode_ref, (void *)b.data)) {
761                         ext4_dbg(DEBUG_DIR_IDX,
762                                  DBG_WARN "HTree leaf block checksum failed."
763                                  "Inode: %" PRIu32", "
764                                  "Block: %" PRIu32"\n",
765                                  inode_ref->index,
766                                  leaf_blk_idx);
767                 }
768
769                 /* Linear search inside block */
770                 struct ext4_dir_en *de;
771                 rc = ext4_dir_find_in_block(&b, &fs->sb, name_len, name, &de);
772
773                 /* Found => return it */
774                 if (rc == EOK) {
775                         result->block = b;
776                         result->dentry = de;
777                         goto cleanup;
778                 }
779
780                 /* Not found, leave untouched */
781                 rc2 = ext4_block_set(fs->bdev, &b);
782                 if (rc2 != EOK)
783                         goto cleanup;
784
785                 if (rc != ENOENT)
786                         goto cleanup;
787
788                 /* check if the next block could be checked */
789                 rc = ext4_dir_dx_next_block(inode_ref, hinfo.hash, dx_block,
790                                             &dx_blocks[0]);
791                 if (rc < 0)
792                         goto cleanup;
793         } while (rc == ENOENT);
794
795         /* Entry not found */
796         rc = ENOENT;
797
798 cleanup:
799         /* The whole path must be released (preventing memory leak) */
800         tmp = dx_blocks;
801
802         while (tmp <= dx_block) {
803                 rc2 = ext4_block_set(fs->bdev, &tmp->b);
804                 if (rc == EOK && rc2 != EOK)
805                         rc = rc2;
806                 ++tmp;
807         }
808
809         return rc;
810 }
811
812 #if CONFIG_DIR_INDEX_COMB_SORT
813 #define SWAP_ENTRY(se1, se2)                                                   \
814         do {                                                                   \
815                 struct ext4_dx_sort_entry tmp = se1;                           \
816                 se1 = se2;                                                     \
817                 se2 = tmp;                                                     \
818         \
819 } while (0)
820
821 static void comb_sort(struct ext4_dx_sort_entry *se, uint32_t count)
822 {
823         struct ext4_dx_sort_entry *p, *q, *top = se + count - 1;
824         bool more;
825         /* Combsort */
826         while (count > 2) {
827                 count = (count * 10) / 13;
828                 if (count - 9 < 2)
829                         count = 11;
830                 for (p = top, q = p - count; q >= se; p--, q--)
831                         if (p->hash < q->hash)
832                                 SWAP_ENTRY(*p, *q);
833         }
834         /* Bubblesort */
835         do {
836                 more = 0;
837                 q = top;
838                 while (q-- > se) {
839                         if (q[1].hash >= q[0].hash)
840                                 continue;
841                         SWAP_ENTRY(*(q + 1), *q);
842                         more = 1;
843                 }
844         } while (more);
845 }
846 #else
847
848 /**@brief  Compare function used to pass in quicksort implementation.
849  *         It can compare two entries by hash value.
850  * @param arg1  First entry
851  * @param arg2  Second entry
852  * @param dummy Unused parameter, can be NULL
853  *
854  * @return Classic compare result
855  *         (0: equal, -1: arg1 < arg2, 1: arg1 > arg2)
856  */
857 static int ext4_dir_dx_entry_comparator(const void *arg1, const void *arg2)
858 {
859         struct ext4_dx_sort_entry *entry1 = (void *)arg1;
860         struct ext4_dx_sort_entry *entry2 = (void *)arg2;
861
862         if (entry1->hash == entry2->hash)
863                 return 0;
864
865         if (entry1->hash < entry2->hash)
866                 return -1;
867         else
868                 return 1;
869 }
870 #endif
871
872 /**@brief  Insert new index entry to block.
873  *         Note that space for new entry must be checked by caller.
874  * @param inode_ref   Directory i-node
875  * @param index_block Block where to insert new entry
876  * @param hash        Hash value covered by child node
877  * @param iblock      Logical number of child block
878  *
879  */
880 static void
881 ext4_dir_dx_insert_entry(struct ext4_inode_ref *inode_ref __unused,
882                          struct ext4_dir_idx_block *index_block,
883                          uint32_t hash, uint32_t iblock)
884 {
885         struct ext4_dir_idx_entry *old_index_entry = index_block->position;
886         struct ext4_dir_idx_entry *new_index_entry = old_index_entry + 1;
887         struct ext4_dir_idx_climit *climit = (void *)index_block->entries;
888         struct ext4_dir_idx_entry *start_index = index_block->entries;
889         uint32_t count = ext4_dir_dx_climit_get_count(climit);
890
891         size_t bytes;
892         bytes = (uint8_t *)(start_index + count) - (uint8_t *)(new_index_entry);
893
894         memmove(new_index_entry + 1, new_index_entry, bytes);
895
896         ext4_dir_dx_entry_set_block(new_index_entry, iblock);
897         ext4_dir_dx_entry_set_hash(new_index_entry, hash);
898         ext4_dir_dx_climit_set_count(climit, count + 1);
899         ext4_dir_set_dx_csum(inode_ref, (void *)index_block->b.data);
900         ext4_bcache_set_dirty(index_block->b.buf);
901 }
902
903 /**@brief Split directory entries to two parts preventing node overflow.
904  * @param inode_ref      Directory i-node
905  * @param hinfo          Hash info
906  * @param old_data_block Block with data to be split
907  * @param index_block    Block where index entries are located
908  * @param new_data_block Output value for newly allocated data block
909  */
910 static int ext4_dir_dx_split_data(struct ext4_inode_ref *inode_ref,
911                                   struct ext4_hash_info *hinfo,
912                                   struct ext4_block *old_data_block,
913                                   struct ext4_dir_idx_block *index_block,
914                                   struct ext4_block *new_data_block)
915 {
916         int rc = EOK;
917         struct ext4_sblock *sb = &inode_ref->fs->sb;
918         uint32_t block_size = ext4_sb_get_block_size(&inode_ref->fs->sb);
919
920         /* Allocate buffer for directory entries */
921         uint8_t *entry_buffer = malloc(block_size);
922         if (entry_buffer == NULL)
923                 return ENOMEM;
924
925         /* dot entry has the smallest size available */
926         uint32_t max_ecnt = block_size / sizeof(struct ext4_dir_idx_dot_en);
927
928         /* Allocate sort entry */
929         struct ext4_dx_sort_entry *sort;
930
931         sort = malloc(max_ecnt * sizeof(struct ext4_dx_sort_entry));
932         if (sort == NULL) {
933                 free(entry_buffer);
934                 return ENOMEM;
935         }
936
937         uint32_t idx = 0;
938         uint32_t real_size = 0;
939
940         /* Initialize hinfo */
941         struct ext4_hash_info hinfo_tmp;
942         memcpy(&hinfo_tmp, hinfo, sizeof(struct ext4_hash_info));
943
944         /* Load all valid entries to the buffer */
945         struct ext4_dir_en *de = (void *)old_data_block->data;
946         uint8_t *entry_buffer_ptr = entry_buffer;
947         while ((void *)de < (void *)(old_data_block->data + block_size)) {
948                 /* Read only valid entries */
949                 if (ext4_dir_en_get_inode(de) && de->name_len) {
950                         uint8_t len = ext4_dir_en_get_name_len(sb, de);
951                         rc = ext4_dir_dx_hash_string(&hinfo_tmp, len,
952                                                      (char *)de->name);
953                         if (rc != EOK) {
954                                 free(sort);
955                                 free(entry_buffer);
956                                 return rc;
957                         }
958
959                         uint32_t rec_len = 8 + len;
960                         if ((rec_len % 4) != 0)
961                                 rec_len += 4 - (rec_len % 4);
962
963                         memcpy(entry_buffer_ptr, de, rec_len);
964
965                         sort[idx].dentry = entry_buffer_ptr;
966                         sort[idx].rec_len = rec_len;
967                         sort[idx].hash = hinfo_tmp.hash;
968
969                         entry_buffer_ptr += rec_len;
970                         real_size += rec_len;
971                         idx++;
972                 }
973
974                 size_t elen = ext4_dir_en_get_entry_len(de);
975                 de = (void *)((uint8_t *)de + elen);
976         }
977
978 /* Sort all entries */
979 #if CONFIG_DIR_INDEX_COMB_SORT
980         comb_sort(sort, idx);
981 #else
982         qsort(sort, idx, sizeof(struct ext4_dx_sort_entry),
983               ext4_dir_dx_entry_comparator);
984 #endif
985         /* Allocate new block for store the second part of entries */
986         ext4_fsblk_t new_fblock;
987         uint32_t new_iblock;
988         rc = ext4_fs_append_inode_dblk(inode_ref, &new_fblock, &new_iblock);
989         if (rc != EOK) {
990                 free(sort);
991                 free(entry_buffer);
992                 return rc;
993         }
994
995         /* Load new block */
996         struct ext4_block new_data_block_tmp;
997         rc = ext4_block_get_noread(inode_ref->fs->bdev, &new_data_block_tmp,
998                                    new_fblock);
999         if (rc != EOK) {
1000                 free(sort);
1001                 free(entry_buffer);
1002                 return rc;
1003         }
1004
1005         /*
1006          * Distribute entries to two blocks (by size)
1007          * - compute the half
1008          */
1009         uint32_t new_hash = 0;
1010         uint32_t current_size = 0;
1011         uint32_t mid = 0;
1012         uint32_t i;
1013         for (i = 0; i < idx; ++i) {
1014                 if ((current_size + sort[i].rec_len) > (block_size / 2)) {
1015                         new_hash = sort[i].hash;
1016                         mid = i;
1017                         break;
1018                 }
1019
1020                 current_size += sort[i].rec_len;
1021         }
1022
1023         /* Check hash collision */
1024         uint32_t continued = 0;
1025         if (new_hash == sort[mid - 1].hash)
1026                 continued = 1;
1027
1028         uint32_t off = 0;
1029         void *ptr;
1030         if (ext4_sb_feature_ro_com(sb, EXT4_FRO_COM_METADATA_CSUM))
1031                 block_size -= sizeof(struct ext4_dir_entry_tail);
1032
1033         /* First part - to the old block */
1034         for (i = 0; i < mid; ++i) {
1035                 ptr = old_data_block->data + off;
1036                 memcpy(ptr, sort[i].dentry, sort[i].rec_len);
1037
1038                 struct ext4_dir_en *t = ptr;
1039                 if (i < (mid - 1))
1040                         ext4_dir_en_set_entry_len(t, sort[i].rec_len);
1041                 else
1042                         ext4_dir_en_set_entry_len(t, block_size - off);
1043
1044                 off += sort[i].rec_len;
1045         }
1046
1047         /* Second part - to the new block */
1048         off = 0;
1049         for (i = mid; i < idx; ++i) {
1050                 ptr = new_data_block_tmp.data + off;
1051                 memcpy(ptr, sort[i].dentry, sort[i].rec_len);
1052
1053                 struct ext4_dir_en *t = ptr;
1054                 if (i < (idx - 1))
1055                         ext4_dir_en_set_entry_len(t, sort[i].rec_len);
1056                 else
1057                         ext4_dir_en_set_entry_len(t, block_size - off);
1058
1059                 off += sort[i].rec_len;
1060         }
1061
1062         block_size = ext4_sb_get_block_size(&inode_ref->fs->sb);
1063
1064         /* Do some steps to finish operation */
1065         sb = &inode_ref->fs->sb;
1066         if (ext4_sb_feature_ro_com(sb, EXT4_FRO_COM_METADATA_CSUM)) {
1067                 struct ext4_dir_entry_tail *t;
1068
1069                 t = EXT4_DIRENT_TAIL(old_data_block->data, block_size);
1070                 ext4_dir_init_entry_tail(t);
1071                 t = EXT4_DIRENT_TAIL(new_data_block_tmp.data, block_size);
1072                 ext4_dir_init_entry_tail(t);
1073         }
1074         ext4_dir_set_csum(inode_ref, (void *)old_data_block->data);
1075         ext4_dir_set_csum(inode_ref, (void *)new_data_block_tmp.data);
1076         ext4_bcache_set_dirty(old_data_block->buf);
1077         ext4_bcache_set_dirty(new_data_block_tmp.buf);
1078
1079         free(sort);
1080         free(entry_buffer);
1081
1082         ext4_dir_dx_insert_entry(inode_ref, index_block, new_hash + continued,
1083                                 new_iblock);
1084
1085         *new_data_block = new_data_block_tmp;
1086         return EOK;
1087 }
1088
1089 /**@brief  Split index node and maybe some parent nodes in the tree hierarchy.
1090  * @param inode_ref Directory i-node
1091  * @param dx_blocks Array with path from root to leaf node
1092  * @param dx_block  Leaf block to be split if needed
1093  * @return Error code
1094  */
1095 static int
1096 ext4_dir_dx_split_index(struct ext4_inode_ref *ino_ref,
1097                         struct ext4_dir_idx_block *dx_blks,
1098                         struct ext4_dir_idx_block *dxb,
1099                         struct ext4_dir_idx_block **new_dx_block)
1100 {
1101         struct ext4_sblock *sb = &ino_ref->fs->sb;
1102         struct ext4_dir_idx_entry *e;
1103         int r;
1104
1105         uint32_t block_size = ext4_sb_get_block_size(&ino_ref->fs->sb);
1106         uint32_t entry_space = block_size - sizeof(struct ext4_fake_dir_entry);
1107         uint32_t node_limit =  entry_space / sizeof(struct ext4_dir_idx_entry);
1108
1109         bool meta_csum = ext4_sb_feature_ro_com(sb, EXT4_FRO_COM_METADATA_CSUM);
1110
1111         if (dxb == dx_blks)
1112                 e = ((struct ext4_dir_idx_root *)dxb->b.data)->en;
1113         else
1114                 e = ((struct ext4_dir_idx_node *)dxb->b.data)->entries;
1115
1116         struct ext4_dir_idx_climit *climit = (struct ext4_dir_idx_climit *)e;
1117
1118         uint16_t leaf_limit = ext4_dir_dx_climit_get_limit(climit);
1119         uint16_t leaf_count = ext4_dir_dx_climit_get_count(climit);
1120
1121         /* Check if is necessary to split index block */
1122         if (leaf_limit == leaf_count) {
1123                 struct ext4_dir_idx_entry *ren;
1124                 ptrdiff_t levels = dxb - dx_blks;
1125
1126                 ren = ((struct ext4_dir_idx_root *)dx_blks[0].b.data)->en;
1127                 struct ext4_dir_idx_climit *rclimit = (void *)ren;
1128                 uint16_t root_limit = ext4_dir_dx_climit_get_limit(rclimit);
1129                 uint16_t root_count = ext4_dir_dx_climit_get_count(rclimit);
1130
1131
1132                 /* Linux limitation */
1133                 if ((levels > 0) && (root_limit == root_count))
1134                         return ENOSPC;
1135
1136                 /* Add new block to directory */
1137                 ext4_fsblk_t new_fblk;
1138                 uint32_t new_iblk;
1139                 r = ext4_fs_append_inode_dblk(ino_ref, &new_fblk, &new_iblk);
1140                 if (r != EOK)
1141                         return r;
1142
1143                 /* load new block */
1144                 struct ext4_block b;
1145                 r = ext4_block_get_noread(ino_ref->fs->bdev, &b, new_fblk);
1146                 if (r != EOK)
1147                         return r;
1148
1149                 struct ext4_dir_idx_node *new_node = (void *)b.data;
1150                 struct ext4_dir_idx_entry *new_en = new_node->entries;
1151
1152                 memset(&new_node->fake, 0, sizeof(struct ext4_fake_dir_entry));
1153                 new_node->fake.entry_length = block_size;
1154
1155                 /* Split leaf node */
1156                 if (levels > 0) {
1157                         uint32_t count_left = leaf_count / 2;
1158                         uint32_t count_right = leaf_count - count_left;
1159                         uint32_t hash_right;
1160                         size_t sz;
1161
1162                         struct ext4_dir_idx_climit *left_climit;
1163                         struct ext4_dir_idx_climit *right_climit;
1164
1165                         hash_right = ext4_dir_dx_entry_get_hash(e + count_left);
1166                         /* Copy data to new node */
1167                         sz = count_right * sizeof(struct ext4_dir_idx_entry);
1168                         memcpy(new_en, e + count_left, sz);
1169
1170                         /* Initialize new node */
1171                         left_climit = (struct ext4_dir_idx_climit *)e;
1172                         right_climit = (struct ext4_dir_idx_climit *)new_en;
1173
1174                         ext4_dir_dx_climit_set_count(left_climit, count_left);
1175                         ext4_dir_dx_climit_set_count(right_climit, count_right);
1176
1177                         if (meta_csum)
1178                                 entry_space -= sizeof(struct ext4_dir_idx_tail);
1179
1180                         ext4_dir_dx_climit_set_limit(right_climit, node_limit);
1181
1182                         /* Which index block is target for new entry */
1183                         uint32_t position_index =
1184                             (dxb->position - dxb->entries);
1185                         if (position_index >= count_left) {
1186                                 ext4_dir_set_dx_csum(
1187                                                 ino_ref,
1188                                                 (struct ext4_dir_en *)
1189                                                 dxb->b.data);
1190                                 ext4_bcache_set_dirty(dxb->b.buf);
1191
1192                                 struct ext4_block block_tmp = dxb->b;
1193
1194                                 dxb->b = b;
1195
1196                                 dxb->position =
1197                                     new_en + position_index - count_left;
1198                                 dxb->entries = new_en;
1199
1200                                 b = block_tmp;
1201                         }
1202
1203                         /* Finally insert new entry */
1204                         ext4_dir_dx_insert_entry(ino_ref, dx_blks, hash_right,
1205                                                  new_iblk);
1206                         ext4_dir_set_dx_csum(ino_ref, (void*)dx_blks[0].b.data);
1207                         ext4_dir_set_dx_csum(ino_ref, (void*)dx_blks[1].b.data);
1208                         ext4_bcache_set_dirty(dx_blks[0].b.buf);
1209                         ext4_bcache_set_dirty(dx_blks[1].b.buf);
1210
1211                         ext4_dir_set_dx_csum(ino_ref, (void *)b.data);
1212                         ext4_bcache_set_dirty(b.buf);
1213                         return ext4_block_set(ino_ref->fs->bdev, &b);
1214                 } else {
1215                         size_t sz;
1216                         /* Copy data from root to child block */
1217                         sz = leaf_count * sizeof(struct ext4_dir_idx_entry);
1218                         memcpy(new_en, e, sz);
1219
1220                         struct ext4_dir_idx_climit *new_climit = (void*)new_en;
1221                         if (meta_csum)
1222                                 entry_space -= sizeof(struct ext4_dir_idx_tail);
1223
1224                         ext4_dir_dx_climit_set_limit(new_climit, node_limit);
1225
1226                         /* Set values in root node */
1227                         struct ext4_dir_idx_climit *new_root_climit = (void *)e;
1228
1229                         ext4_dir_dx_climit_set_count(new_root_climit, 1);
1230                         ext4_dir_dx_entry_set_block(e, new_iblk);
1231
1232                         struct ext4_dir_idx_root *r = (void *)dx_blks[0].b.data;
1233                         r->info.indirect_levels = 1;
1234
1235                         /* Add new entry to the path */
1236                         dxb = dx_blks + 1;
1237                         dxb->position = dx_blks->position - e + new_en;
1238                         dxb->entries = new_en;
1239                         dxb->b = b;
1240                         *new_dx_block = dxb;
1241
1242                         ext4_dir_set_dx_csum(ino_ref, (void*)dx_blks[0].b.data);
1243                         ext4_dir_set_dx_csum(ino_ref, (void*)dx_blks[1].b.data);
1244                         ext4_bcache_set_dirty(dx_blks[0].b.buf);
1245                         ext4_bcache_set_dirty(dx_blks[1].b.buf);
1246                 }
1247         }
1248
1249         return EOK;
1250 }
1251
1252 int ext4_dir_dx_add_entry(struct ext4_inode_ref *parent,
1253                           struct ext4_inode_ref *child, const char *name)
1254 {
1255         int rc2 = EOK;
1256         int r;
1257         /* Get direct block 0 (index root) */
1258         ext4_fsblk_t rblock_addr;
1259         r =  ext4_fs_get_inode_dblk_idx(parent, 0, &rblock_addr, false);
1260         if (r != EOK)
1261                 return r;
1262
1263         struct ext4_fs *fs = parent->fs;
1264         struct ext4_block root_blk;
1265
1266         r = ext4_block_get(fs->bdev, &root_blk, rblock_addr);
1267         if (r != EOK)
1268                 return r;
1269
1270         if (!ext4_dir_dx_csum_verify(parent, (void*)root_blk.data)) {
1271                 ext4_dbg(DEBUG_DIR_IDX,
1272                          DBG_WARN "HTree root checksum failed."
1273                          "Inode: %" PRIu32", "
1274                          "Block: %" PRIu32"\n",
1275                          parent->index,
1276                          (uint32_t)0);
1277         }
1278
1279         /* Initialize hinfo structure (mainly compute hash) */
1280         uint32_t name_len = strlen(name);
1281         struct ext4_hash_info hinfo;
1282         r = ext4_dir_hinfo_init(&hinfo, &root_blk, &fs->sb, name_len, name);
1283         if (r != EOK) {
1284                 ext4_block_set(fs->bdev, &root_blk);
1285                 return EXT4_ERR_BAD_DX_DIR;
1286         }
1287
1288         /*
1289          * Hardcoded number 2 means maximum height of index
1290          * tree defined in Linux.
1291          */
1292         struct ext4_dir_idx_block dx_blks[2];
1293         struct ext4_dir_idx_block *dx_blk;
1294         struct ext4_dir_idx_block *dx_it;
1295
1296         r = ext4_dir_dx_get_leaf(&hinfo, parent, &root_blk, &dx_blk, dx_blks);
1297         if (r != EOK) {
1298                 r = EXT4_ERR_BAD_DX_DIR;
1299                 goto release_index;
1300         }
1301
1302         /* Try to insert to existing data block */
1303         uint32_t leaf_block_idx = ext4_dir_dx_entry_get_block(dx_blk->position);
1304         ext4_fsblk_t leaf_block_addr;
1305         r = ext4_fs_get_inode_dblk_idx(parent, leaf_block_idx,
1306                                                 &leaf_block_addr, false);
1307         if (r != EOK)
1308                 goto release_index;
1309
1310         /*
1311          * Check if there is needed to split index node
1312          * (and recursively also parent nodes)
1313          */
1314         r = ext4_dir_dx_split_index(parent, dx_blks, dx_blk, &dx_blk);
1315         if (r != EOK)
1316                 goto release_target_index;
1317
1318         struct ext4_block target_block;
1319         r = ext4_block_get(fs->bdev, &target_block, leaf_block_addr);
1320         if (r != EOK)
1321                 goto release_index;
1322
1323         if (!ext4_dir_csum_verify(parent,(void *)target_block.data)) {
1324                 ext4_dbg(DEBUG_DIR_IDX,
1325                                 DBG_WARN "HTree leaf block checksum failed."
1326                                 "Inode: %" PRIu32", "
1327                                 "Block: %" PRIu32"\n",
1328                                 parent->index,
1329                                 leaf_block_idx);
1330         }
1331
1332         /* Check if insert operation passed */
1333         r = ext4_dir_try_insert_entry(&fs->sb, parent, &target_block, child,
1334                                         name, name_len);
1335         if (r == EOK)
1336                 goto release_target_index;
1337
1338         /* Split entries to two blocks (includes sorting by hash value) */
1339         struct ext4_block new_block;
1340         r = ext4_dir_dx_split_data(parent, &hinfo, &target_block, dx_blk,
1341                                     &new_block);
1342         if (r != EOK) {
1343                 rc2 = r;
1344                 goto release_target_index;
1345         }
1346
1347         /* Where to save new entry */
1348         uint32_t blk_hash = ext4_dir_dx_entry_get_hash(dx_blk->position + 1);
1349         if (hinfo.hash >= blk_hash)
1350                 r = ext4_dir_try_insert_entry(&fs->sb, parent, &new_block,
1351                                                 child, name, name_len);
1352         else
1353                 r = ext4_dir_try_insert_entry(&fs->sb, parent, &target_block,
1354                                                 child, name, name_len);
1355
1356         /* Cleanup */
1357         r = ext4_block_set(fs->bdev, &new_block);
1358         if (r != EOK)
1359                 return r;
1360
1361 /* Cleanup operations */
1362
1363 release_target_index:
1364         rc2 = r;
1365
1366         r = ext4_block_set(fs->bdev, &target_block);
1367         if (r != EOK)
1368                 return r;
1369
1370 release_index:
1371         if (r != EOK)
1372                 rc2 = r;
1373
1374         dx_it = dx_blks;
1375
1376         while (dx_it <= dx_blk) {
1377                 r = ext4_block_set(fs->bdev, &dx_it->b);
1378                 if (r != EOK)
1379                         return r;
1380
1381                 dx_it++;
1382         }
1383
1384         return rc2;
1385 }
1386
1387 int ext4_dir_dx_reset_parent_inode(struct ext4_inode_ref *dir,
1388                                    uint32_t parent_inode)
1389 {
1390         /* Load block 0, where will be index root located */
1391         ext4_fsblk_t fblock;
1392         int rc = ext4_fs_get_inode_dblk_idx(dir, 0, &fblock, false);
1393         if (rc != EOK)
1394                 return rc;
1395
1396         struct ext4_block block;
1397         rc = ext4_block_get(dir->fs->bdev, &block, fblock);
1398         if (rc != EOK)
1399                 return rc;
1400
1401         if (!ext4_dir_dx_csum_verify(dir, (void *)block.data)) {
1402                 ext4_dbg(DEBUG_DIR_IDX,
1403                          DBG_WARN "HTree root checksum failed."
1404                          "Inode: %" PRIu32", "
1405                          "Block: %" PRIu32"\n",
1406                          dir->index,
1407                          (uint32_t)0);
1408         }
1409
1410         /* Initialize pointers to data structures */
1411         struct ext4_dir_idx_root *root = (void *)block.data;
1412
1413         /* Fill the inode field with a new parent ino. */
1414         ext4_dx_dot_en_set_inode(&root->dots[1], parent_inode);
1415
1416         ext4_dir_set_dx_csum(dir, (void *)block.data);
1417         ext4_bcache_set_dirty(block.buf);
1418
1419         return ext4_block_set(dir->fs->bdev, &block);
1420 }
1421
1422 /**
1423  * @}
1424  */