2 * Copyright (c) 2013 Grzegorz Kostka (kostka.grzegorz@gmail.com)
6 * Copyright (c) 2012 Martin Sucha
7 * Copyright (c) 2012 Frantisek Princ
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
14 * - Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * - Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * - The name of the author may not be used to endorse or promote products
20 * derived from this software without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 /** @addtogroup lwext4
39 * @brief More complex filesystem functions.
42 #include "ext4_config.h"
43 #include "ext4_extent.h"
44 #include "ext4_inode.h"
45 #include "ext4_super.h"
46 #include "ext4_crc32c.h"
47 #include "ext4_blockdev.h"
48 #include "ext4_balloc.h"
54 #if !CONFIG_EXTENT_FULL
56 /**@brief Binary search in extent index node.
57 * @param header Extent header of index node
58 * @param index Output value - found index will be set here
59 * @param iblock Logical block number to find in index node */
60 static void ext4_extent_binsearch_idx(struct ext4_extent_header *header,
61 struct ext4_extent_index **index,
64 struct ext4_extent_index *r;
65 struct ext4_extent_index *l;
66 struct ext4_extent_index *m;
68 uint16_t entries_count = ext4_extent_header_get_entries_count(header);
70 /* Initialize bounds */
71 l = EXT4_EXTENT_FIRST_INDEX(header) + 1;
72 r = EXT4_EXTENT_FIRST_INDEX(header) + entries_count - 1;
74 /* Do binary search */
77 uint32_t first_block = ext4_extent_index_get_first_block(m);
79 if (iblock < first_block)
85 /* Set output value */
89 /**@brief Binary search in extent leaf node.
90 * @param header Extent header of leaf node
91 * @param extent Output value - found extent will be set here,
92 * or NULL if node is empty
93 * @param iblock Logical block number to find in leaf node */
94 static void ext4_extent_binsearch(struct ext4_extent_header *header,
95 struct ext4_extent **extent, uint32_t iblock)
97 struct ext4_extent *r;
98 struct ext4_extent *l;
99 struct ext4_extent *m;
101 uint16_t entries_count = ext4_extent_header_get_entries_count(header);
103 if (entries_count == 0) {
104 /* this leaf is empty */
109 /* Initialize bounds */
110 l = EXT4_EXTENT_FIRST(header) + 1;
111 r = EXT4_EXTENT_FIRST(header) + entries_count - 1;
113 /* Do binary search */
116 uint32_t first_block = ext4_extent_get_first_block(m);
118 if (iblock < first_block)
124 /* Set output value */
128 static uint32_t ext4_ext_block_csum(struct ext4_inode_ref *inode_ref,
129 struct ext4_extent_header *eh)
131 uint32_t checksum = 0;
132 struct ext4_sblock *sb = &inode_ref->fs->sb;
134 if (ext4_sb_has_feature_read_only(sb,
135 EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) {
136 uint32_t ino_index = to_le32(inode_ref->index);
138 to_le32(ext4_inode_get_generation(inode_ref->inode));
139 /* First calculate crc32 checksum against fs uuid */
140 checksum = ext4_crc32c(~0, sb->uuid, sizeof(sb->uuid));
141 /* Then calculate crc32 checksum against inode number
142 * and inode generation */
143 checksum = ext4_crc32c(checksum, &ino_index,
145 checksum = ext4_crc32c(checksum, &ino_gen,
147 /* Finally calculate crc32 checksum against
148 * the entire extent block up to the checksum field */
149 checksum = ext4_crc32c(checksum, eh,
150 EXT4_EXTENT_TAIL_OFFSET(eh));
155 static struct ext4_extent_header *ext_block_hdr(struct ext4_block *block)
157 return (struct ext4_extent_header *)block->data;
160 static struct ext4_extent_tail *
161 find_ext4_extent_tail(struct ext4_extent_header *eh)
163 return (struct ext4_extent_tail *)(((char *)eh) +
164 EXT4_EXTENT_TAIL_OFFSET(eh));
169 * Currently we do not verify the checksum of extent
170 * (only the case in ext4_extent.c)
173 static void ext4_extent_block_csum_set(struct ext4_inode_ref *inode_ref,
174 struct ext4_extent_header *eh)
176 struct ext4_extent_tail *tail;
178 tail = find_ext4_extent_tail(eh);
179 tail->et_checksum = to_le32(ext4_ext_block_csum(inode_ref, eh));
182 /**@brief Get physical block in the extent tree by logical block number.
183 * There is no need to save path in the tree during this algorithm.
184 * @param inode_ref I-node to load block from
185 * @param iblock Logical block number to find
186 * @param fblock Output value for physical block number
187 * @return Error code*/
189 ext4_extent_find_block(struct ext4_inode_ref *inode_ref, uint32_t iblock,
190 ext4_fsblk_t *fblock)
193 /* Compute bound defined by i-node size */
194 uint64_t inode_size =
195 ext4_inode_get_size(&inode_ref->fs->sb, inode_ref->inode);
197 uint32_t block_size = ext4_sb_get_block_size(&inode_ref->fs->sb);
199 uint32_t last_idx = (inode_size - 1) / block_size;
201 /* Check if requested iblock is not over size of i-node */
202 if (iblock > last_idx) {
207 struct ext4_block block;
210 /* Walk through extent tree */
211 struct ext4_extent_header *header =
212 ext4_inode_get_extent_header(inode_ref->inode);
214 while (ext4_extent_header_get_depth(header) != 0) {
215 /* Search index in node */
216 struct ext4_extent_index *index;
217 ext4_extent_binsearch_idx(header, &index, iblock);
219 /* Load child node and set values for the next iteration */
220 uint64_t child = ext4_extent_index_get_leaf(index);
223 rc = ext4_block_set(inode_ref->fs->bdev, &block);
228 int rc = ext4_block_get(inode_ref->fs->bdev, &block, child);
232 header = (struct ext4_extent_header *)block.data;
235 /* Search extent in the leaf block */
236 struct ext4_extent *extent = NULL;
237 ext4_extent_binsearch(header, &extent, iblock);
239 /* Prevent empty leaf */
240 if (extent == NULL) {
243 /* Compute requested physical block address */
244 ext4_fsblk_t phys_block;
245 uint32_t first = ext4_extent_get_first_block(extent);
246 phys_block = ext4_extent_get_start(extent) + iblock - first;
248 *fblock = phys_block;
253 rc = ext4_block_set(inode_ref->fs->bdev, &block);
261 /**@brief Find extent for specified iblock.
262 * This function is used for finding block in the extent tree with
263 * saving the path through the tree for possible future modifications.
264 * @param inode_ref I-node to read extent tree from
265 * @param iblock Iblock to find extent for
266 * @param ret_path Output value for loaded path from extent tree
267 * @return Error code */
268 static int ext4_extent_find_extent(struct ext4_inode_ref *inode_ref,
270 struct ext4_extent_path **ret_path)
272 struct ext4_extent_header *eh =
273 ext4_inode_get_extent_header(inode_ref->inode);
275 uint16_t depth = ext4_extent_header_get_depth(eh);
277 struct ext4_extent_path *tmp_path;
279 /* Added 2 for possible tree growing */
280 tmp_path = malloc(sizeof(struct ext4_extent_path) * (depth + 2));
281 if (tmp_path == NULL)
284 /* Initialize structure for algorithm start */
285 tmp_path[0].block = inode_ref->block;
286 tmp_path[0].header = eh;
288 /* Walk through the extent tree */
291 while (ext4_extent_header_get_depth(eh) != 0) {
292 /* Search index in index node by iblock */
293 ext4_extent_binsearch_idx(tmp_path[pos].header,
294 &tmp_path[pos].index, iblock);
296 tmp_path[pos].depth = depth;
297 tmp_path[pos].extent = NULL;
299 ext4_assert(tmp_path[pos].index != 0);
301 /* Load information for the next iteration */
303 ext4_extent_index_get_leaf(tmp_path[pos].index);
305 struct ext4_block block;
306 rc = ext4_block_get(inode_ref->fs->bdev, &block, fblock);
312 eh = (struct ext4_extent_header *)block.data;
313 tmp_path[pos].block = block;
314 tmp_path[pos].header = eh;
317 tmp_path[pos].depth = 0;
318 tmp_path[pos].extent = NULL;
319 tmp_path[pos].index = NULL;
321 /* Find extent in the leaf node */
322 ext4_extent_binsearch(tmp_path[pos].header, &tmp_path[pos].extent,
324 *ret_path = tmp_path;
331 * From 1: 0 is a block with inode data
333 for (i = 1; i < tmp_path->depth; ++i) {
334 if (tmp_path[i].block.lb_id) {
335 int r = ext4_block_set(inode_ref->fs->bdev,
342 /* Destroy temporary data structure */
348 /**@brief Release extent and all data blocks covered by the extent.
349 * @param inode_ref I-node to release extent and block from
350 * @param extent Extent to release
351 * @return Error code */
352 static int ext4_extent_release(struct ext4_inode_ref *inode_ref,
353 struct ext4_extent *extent)
355 /* Compute number of the first physical block to release */
356 uint64_t start = ext4_extent_get_start(extent);
357 uint16_t block_count = ext4_extent_get_block_count(extent);
359 return ext4_balloc_free_blocks(inode_ref, start, block_count);
362 /** Recursively release the whole branch of the extent tree.
363 * For each entry of the node release the subbranch and finally release
364 * the node. In the leaf node all extents will be released.
365 * @param inode_ref I-node where the branch is released
366 * @param index Index in the non-leaf node to be released
367 * with the whole subtree
368 * @return Error code */
369 static int ext4_extent_release_branch(struct ext4_inode_ref *inode_ref,
370 struct ext4_extent_index *index)
372 ext4_fsblk_t fblock = ext4_extent_index_get_leaf(index);
374 struct ext4_block block;
375 int rc = ext4_block_get(inode_ref->fs->bdev, &block, fblock);
379 struct ext4_extent_header *header = (void *)block.data;
381 if (ext4_extent_header_get_depth(header)) {
382 /* The node is non-leaf, do recursion */
383 struct ext4_extent_index *idx = EXT4_EXTENT_FIRST_INDEX(header);
385 /* Release all subbranches */
386 for (i = 0; i < ext4_extent_header_get_entries_count(header);
388 rc = ext4_extent_release_branch(inode_ref, idx);
393 /* Leaf node reached */
394 struct ext4_extent *ext = EXT4_EXTENT_FIRST(header);
396 /* Release all extents and stop recursion */
397 for (i = 0; i < ext4_extent_header_get_entries_count(header);
399 rc = ext4_extent_release(inode_ref, ext);
405 /* Release data block where the node was stored */
407 rc = ext4_block_set(inode_ref->fs->bdev, &block);
411 return ext4_balloc_free_block(inode_ref, fblock);
414 int ext4_extent_remove_space(struct ext4_inode_ref *inode_ref, ext4_lblk_t from,
417 if (to != EXT_MAX_BLOCKS)
420 /* Find the first extent to modify */
421 struct ext4_extent_path *path;
423 int rc = ext4_extent_find_extent(inode_ref, from, &path);
427 /* Jump to last item of the path (extent) */
428 struct ext4_extent_path *path_ptr = path;
429 while (path_ptr->depth != 0)
432 ext4_assert(path_ptr->extent != NULL);
434 /* First extent maybe released partially */
435 uint32_t first_iblock = ext4_extent_get_first_block(path_ptr->extent);
436 ext4_fsblk_t first_fblock = ext4_extent_get_start(path_ptr->extent) +
439 uint16_t block_count = ext4_extent_get_block_count(path_ptr->extent);
441 uint16_t delete_count =
443 (ext4_extent_get_start(path_ptr->extent) - first_fblock);
445 /* Release all blocks */
446 rc = ext4_balloc_free_blocks(inode_ref, first_fblock, delete_count);
450 /* Correct counter */
451 block_count -= delete_count;
452 ext4_extent_set_block_count(path_ptr->extent, block_count,
453 EXT4_EXT_IS_UNWRITTEN(path_ptr->extent));
455 /* Initialize the following loop */
457 ext4_extent_header_get_entries_count(path_ptr->header);
458 struct ext4_extent *tmp_ext = path_ptr->extent + 1;
459 struct ext4_extent *stop_ext =
460 EXT4_EXTENT_FIRST(path_ptr->header) + entries;
462 /* If first extent empty, release it */
463 if (block_count == 0)
466 /* Release all successors of the first extent in the same node */
467 while (tmp_ext < stop_ext) {
468 first_fblock = ext4_extent_get_start(tmp_ext);
469 delete_count = ext4_extent_get_block_count(tmp_ext);
471 rc = ext4_balloc_free_blocks(inode_ref, first_fblock,
480 ext4_extent_header_set_entries_count(path_ptr->header, entries);
481 ext4_extent_block_csum_set(inode_ref, ext_block_hdr(&path_ptr->block));
482 path_ptr->block.dirty = true;
484 /* If leaf node is empty, parent entry must be modified */
485 bool remove_parent_record = false;
487 /* Don't release root block (including inode data) !!! */
488 if ((path_ptr != path) && (entries == 0)) {
489 rc = ext4_balloc_free_block(inode_ref, path_ptr->block.lb_id);
493 remove_parent_record = true;
496 /* Jump to the parent */
499 /* Release all successors in all tree levels */
500 while (path_ptr >= path) {
502 ext4_extent_header_get_entries_count(path_ptr->header);
503 struct ext4_extent_index *index = path_ptr->index + 1;
504 struct ext4_extent_index *stop =
505 EXT4_EXTENT_FIRST_INDEX(path_ptr->header) + entries;
507 /* Correct entries count because of changes in the previous
509 if (remove_parent_record)
512 /* Iterate over all entries and release the whole subtrees */
513 while (index < stop) {
514 rc = ext4_extent_release_branch(inode_ref, index);
522 ext4_extent_header_set_entries_count(path_ptr->header, entries);
523 ext4_extent_block_csum_set(inode_ref, ext_block_hdr(&path_ptr->block));
524 path_ptr->block.dirty = true;
526 /* Free the node if it is empty */
527 if ((entries == 0) && (path_ptr != path)) {
528 rc = ext4_balloc_free_block(inode_ref,
529 path_ptr->block.lb_id);
533 /* Mark parent to be checked */
534 remove_parent_record = true;
536 remove_parent_record = false;
542 ext4_extent_header_set_depth(path->header, 0);
547 * starting from 1: 0 is a block with inode data
549 for (i = 1; i <= path->depth; ++i) {
550 if (path[i].block.lb_id) {
552 ext4_block_set(inode_ref->fs->bdev, &path[i].block);
558 /* Destroy temporary data structure */
564 /**@brief Append new extent to the i-node and do some splitting if necessary.
565 * @param inode_ref I-node to append extent to
566 * @param path Path in the extent tree for possible splitting
567 * @param last_path_item Input/output parameter for pointer to the last
568 * valid item in the extent tree path
569 * @param iblock Logical index of block to append extent for
570 * @return Error code */
571 static int ext4_extent_append_extent(struct ext4_inode_ref *inode_ref,
572 struct ext4_extent_path *path,
575 struct ext4_extent_path *path_ptr = path + path->depth;
577 uint32_t block_size = ext4_sb_get_block_size(&inode_ref->fs->sb);
579 /* Start splitting */
580 while (path_ptr > path) {
582 ext4_extent_header_get_entries_count(path_ptr->header);
584 ext4_extent_header_get_max_entries_count(path_ptr->header);
586 if (entries == limit) {
587 /* Full node - allocate block for new one */
588 ext4_fsblk_t goal, fblock;
589 int rc = ext4_fs_indirect_find_goal(inode_ref, &goal);
593 rc = ext4_balloc_alloc_block(inode_ref, goal, &fblock);
597 struct ext4_block block;
599 ext4_block_get(inode_ref->fs->bdev, &block, fblock);
601 ext4_balloc_free_block(inode_ref, fblock);
605 /* Put back not modified old block */
606 rc = ext4_block_set(inode_ref->fs->bdev,
609 ext4_balloc_free_block(inode_ref, fblock);
613 /* Initialize newly allocated block and remember it */
614 memset(block.data, 0, block_size);
615 path_ptr->block = block;
617 /* Update pointers in extent path structure */
618 path_ptr->header = (void *)block.data;
619 if (path_ptr->depth) {
621 EXT4_EXTENT_FIRST_INDEX(path_ptr->header);
622 ext4_extent_index_set_first_block(
623 path_ptr->index, iblock);
624 ext4_extent_index_set_leaf(
626 (path_ptr + 1)->block.lb_id);
627 limit = (block_size -
628 sizeof(struct ext4_extent_header)) /
629 sizeof(struct ext4_extent_index);
632 EXT4_EXTENT_FIRST(path_ptr->header);
633 ext4_extent_set_first_block(path_ptr->extent,
635 limit = (block_size -
636 sizeof(struct ext4_extent_header)) /
637 sizeof(struct ext4_extent);
640 /* Initialize on-disk structure (header) */
641 ext4_extent_header_set_entries_count(path_ptr->header,
643 ext4_extent_header_set_max_entries_count(
644 path_ptr->header, limit);
645 ext4_extent_header_set_magic(path_ptr->header,
647 ext4_extent_header_set_depth(path_ptr->header,
649 ext4_extent_header_set_generation(path_ptr->header, 0);
651 ext4_extent_block_csum_set(inode_ref, ext_block_hdr(&path_ptr->block));
652 path_ptr->block.dirty = true;
654 /* Jump to the preceding item */
657 /* Node with free space */
658 if (path_ptr->depth) {
660 EXT4_EXTENT_FIRST_INDEX(path_ptr->header) +
662 ext4_extent_index_set_first_block(
663 path_ptr->index, iblock);
664 ext4_extent_index_set_leaf(
666 (path_ptr + 1)->block.lb_id);
669 EXT4_EXTENT_FIRST(path_ptr->header) +
671 ext4_extent_set_first_block(path_ptr->extent,
675 ext4_extent_header_set_entries_count(path_ptr->header,
677 ext4_extent_block_csum_set(inode_ref, ext_block_hdr(&path_ptr->block));
678 path_ptr->block.dirty = true;
680 /* No more splitting needed */
685 ext4_assert(path_ptr == path);
687 /* Should be the root split too? */
689 uint16_t entries = ext4_extent_header_get_entries_count(path->header);
690 uint16_t limit = ext4_extent_header_get_max_entries_count(path->header);
692 if (entries == limit) {
693 ext4_fsblk_t goal, new_fblock;
694 int rc = ext4_fs_indirect_find_goal(inode_ref, &goal);
698 rc = ext4_balloc_alloc_block(inode_ref, goal, &new_fblock);
702 struct ext4_block block;
703 rc = ext4_block_get(inode_ref->fs->bdev, &block, new_fblock);
707 /* Initialize newly allocated block */
708 memset(block.data, 0, block_size);
710 /* Move data from root to the new block */
711 memcpy(block.data, inode_ref->inode->blocks,
712 EXT4_INODE_BLOCKS * sizeof(uint32_t));
714 /* Data block is initialized */
716 struct ext4_block *root_block = &path->block;
717 uint16_t root_depth = path->depth;
718 struct ext4_extent_header *root_header = path->header;
720 /* Make space for tree growing */
721 struct ext4_extent_path *new_root = path;
722 struct ext4_extent_path *old_root = path + 1;
725 sizeof(struct ext4_extent_path) * (path->depth + 1);
726 memmove(old_root, new_root, nbytes);
727 memset(new_root, 0, sizeof(struct ext4_extent_path));
729 /* Update old root structure */
730 old_root->block = block;
731 old_root->header = (struct ext4_extent_header *)block.data;
733 /* Add new entry and update limit for entries */
734 if (old_root->depth) {
736 (block_size - sizeof(struct ext4_extent_header)) /
737 sizeof(struct ext4_extent_index);
739 EXT4_EXTENT_FIRST_INDEX(old_root->header) + entries;
740 ext4_extent_index_set_first_block(old_root->index,
742 ext4_extent_index_set_leaf(old_root->index,
743 (old_root + 1)->block.lb_id);
744 old_root->extent = NULL;
747 (block_size - sizeof(struct ext4_extent_header)) /
748 sizeof(struct ext4_extent);
750 EXT4_EXTENT_FIRST(old_root->header) + entries;
751 ext4_extent_set_first_block(old_root->extent, iblock);
752 old_root->index = NULL;
755 ext4_extent_header_set_entries_count(old_root->header,
757 ext4_extent_header_set_max_entries_count(old_root->header,
760 ext4_extent_block_csum_set(inode_ref, ext_block_hdr(&old_root->block));
761 old_root->block.dirty = true;
763 /* Re-initialize new root metadata */
764 new_root->depth = root_depth + 1;
765 new_root->block = *root_block;
766 new_root->header = root_header;
767 new_root->extent = NULL;
768 new_root->index = EXT4_EXTENT_FIRST_INDEX(new_root->header);
770 ext4_extent_header_set_depth(new_root->header, new_root->depth);
772 /* Create new entry in root */
773 ext4_extent_header_set_entries_count(new_root->header, 1);
774 ext4_extent_index_set_first_block(new_root->index, 0);
775 ext4_extent_index_set_leaf(new_root->index, new_fblock);
777 /* Since new_root belongs to on-disk inode,
778 * we don't do checksum here */
779 new_root->block.dirty = true;
783 EXT4_EXTENT_FIRST_INDEX(path->header) + entries;
784 ext4_extent_index_set_first_block(path->index, iblock);
785 ext4_extent_index_set_leaf(path->index,
786 (path + 1)->block.lb_id);
789 EXT4_EXTENT_FIRST(path->header) + entries;
790 ext4_extent_set_first_block(path->extent, iblock);
793 ext4_extent_header_set_entries_count(path->header, entries + 1);
794 /* Since new_root belongs to on-disk inode,
795 * we don't do checksum here */
796 path->block.dirty = true;
802 /**@brief Append data block to the i-node.
803 * This function allocates data block, tries to append it
804 * to some existing extent or creates new extents.
805 * It includes possible extent tree modifications (splitting).
806 * @param inode_ref I-node to append block to
807 * @param iblock Output logical number of newly allocated block
808 * @param fblock Output physical block address of newly allocated block
810 * @return Error code*/
812 ext4_extent_append_block(struct ext4_inode_ref *inode_ref, uint32_t *iblock,
813 ext4_fsblk_t *fblock, bool update_size)
817 struct ext4_sblock *sb = &inode_ref->fs->sb;
818 uint64_t inode_size = ext4_inode_get_size(sb, inode_ref->inode);
819 uint32_t block_size = ext4_sb_get_block_size(sb);
821 /* Calculate number of new logical block */
822 uint32_t new_block_idx = 0;
823 if (inode_size > 0) {
824 if ((inode_size % block_size) != 0)
825 inode_size += block_size - (inode_size % block_size);
827 new_block_idx = inode_size / block_size;
830 /* Load the nearest leaf (with extent) */
831 struct ext4_extent_path *path;
832 int rc = ext4_extent_find_extent(inode_ref, new_block_idx, &path);
836 /* Jump to last item of the path (extent) */
837 struct ext4_extent_path *path_ptr = path;
838 while (path_ptr->depth != 0)
841 /* Add new extent to the node if not present */
842 if (path_ptr->extent == NULL)
845 uint16_t block_count = ext4_extent_get_block_count(path_ptr->extent);
846 uint16_t block_limit = (1 << 15);
848 ext4_fsblk_t phys_block = 0;
849 if (block_count < block_limit) {
850 /* There is space for new block in the extent */
851 if (block_count == 0) {
852 int rc = ext4_fs_indirect_find_goal(inode_ref, &goal);
856 /* Existing extent is empty */
857 rc = ext4_balloc_alloc_block(inode_ref, goal, &phys_block);
861 /* Initialize extent */
862 ext4_extent_set_first_block(path_ptr->extent,
864 ext4_extent_set_start(path_ptr->extent, phys_block);
865 ext4_extent_set_block_count(path_ptr->extent, 1,
870 ext4_inode_set_size(inode_ref->inode,
871 inode_size + block_size);
872 inode_ref->dirty = true;
875 ext4_extent_block_csum_set(inode_ref, ext_block_hdr(&path_ptr->block));
876 path_ptr->block.dirty = true;
881 int rc = ext4_fs_indirect_find_goal(inode_ref, &goal);
885 /* Existing extent contains some blocks */
886 phys_block = ext4_extent_get_start(path_ptr->extent);
888 ext4_extent_get_block_count(path_ptr->extent);
890 /* Check if the following block is free for allocation
893 rc = ext4_balloc_try_alloc_block(inode_ref, phys_block,
899 /* Target is not free, new block must be
900 * appended to new extent
906 ext4_extent_set_block_count(path_ptr->extent,
912 ext4_inode_set_size(inode_ref->inode,
913 inode_size + block_size);
914 inode_ref->dirty = true;
917 ext4_extent_block_csum_set(inode_ref, ext_block_hdr(&path_ptr->block));
918 path_ptr->block.dirty = true;
925 /* Append new extent to the tree */
928 rc = ext4_fs_indirect_find_goal(inode_ref, &goal);
932 /* Allocate new data block */
933 rc = ext4_balloc_alloc_block(inode_ref, goal, &phys_block);
937 /* Append extent for new block (includes tree splitting if needed) */
938 rc = ext4_extent_append_extent(inode_ref, path, new_block_idx);
940 ext4_balloc_free_block(inode_ref, phys_block);
944 uint32_t tree_depth = ext4_extent_header_get_depth(path->header);
945 path_ptr = path + tree_depth;
947 /* Initialize newly created extent */
948 ext4_extent_set_block_count(path_ptr->extent, 1, false);
949 ext4_extent_set_first_block(path_ptr->extent, new_block_idx);
950 ext4_extent_set_start(path_ptr->extent, phys_block);
954 ext4_inode_set_size(inode_ref->inode, inode_size + block_size);
955 inode_ref->dirty = true;
958 ext4_extent_block_csum_set(inode_ref, ext_block_hdr(&path_ptr->block));
959 path_ptr->block.dirty = true;
962 /* Set return values */
963 *iblock = new_block_idx;
964 *fblock = phys_block;
968 * starting from 1: 0 is a block with inode data
970 for (i = 1; i <= path->depth; ++i) {
971 if (path[i].block.lb_id) {
973 ext4_block_set(inode_ref->fs->bdev, &path[i].block);
979 /* Destroy temporary data structure */
985 int ext4_extent_get_blocks(struct ext4_inode_ref *inode_ref, ext4_fsblk_t iblock,
986 ext4_lblk_t max_blocks, ext4_fsblk_t *result, bool create,
987 ext4_lblk_t *blocks_count)
989 uint32_t iblk = iblock;
990 ext4_fsblk_t fblk = 0;
999 r = ext4_extent_find_block(inode_ref, iblk, &fblk);
1001 r = ext4_extent_append_block(inode_ref, &iblk, &fblk, false);