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_blockdev.h"
47 #include "ext4_balloc.h"
52 uint32_t ext4_extent_get_first_block(struct ext4_extent *extent)
54 return to_le32(extent->first_block);
57 void ext4_extent_set_first_block(struct ext4_extent *extent, uint32_t iblock)
59 extent->first_block = to_le32(iblock);
62 uint16_t ext4_extent_get_block_count(struct ext4_extent *extent)
64 return to_le16(extent->block_count);
67 void ext4_extent_set_block_count(struct ext4_extent *extent, uint16_t count)
69 extent->block_count = to_le16(count);
72 uint64_t ext4_extent_get_start(struct ext4_extent *extent)
74 return ((uint64_t)to_le16(extent->start_hi)) << 32 |
75 ((uint64_t)to_le32(extent->start_lo));
78 void ext4_extent_set_start(struct ext4_extent *extent, uint64_t fblock)
80 extent->start_lo = to_le32((fblock << 32) >> 32);
81 extent->start_hi = to_le16((uint16_t)(fblock >> 32));
84 uint32_t ext4_extent_index_get_first_block(struct ext4_extent_index *index)
86 return to_le32(index->first_block);
89 void ext4_extent_index_set_first_block(struct ext4_extent_index *index,
92 index->first_block = to_le32(iblock);
95 uint64_t ext4_extent_index_get_leaf(struct ext4_extent_index *index)
97 return ((uint64_t)to_le16(index->leaf_hi)) << 32 |
98 ((uint64_t)to_le32(index->leaf_lo));
101 void ext4_extent_index_set_leaf(struct ext4_extent_index *index,
104 index->leaf_lo = to_le32((fblock << 32) >> 32);
105 index->leaf_hi = to_le16((uint16_t)(fblock >> 32));
108 uint16_t ext4_extent_header_get_magic(struct ext4_extent_header *header)
110 return to_le16(header->magic);
113 void ext4_extent_header_set_magic(struct ext4_extent_header *header,
116 header->magic = to_le16(magic);
119 uint16_t ext4_extent_header_get_entries_count(struct ext4_extent_header *header)
121 return to_le16(header->entries_count);
124 void ext4_extent_header_set_entries_count(struct ext4_extent_header *header,
127 header->entries_count = to_le16(count);
131 ext4_extent_header_get_max_entries_count(struct ext4_extent_header *header)
133 return to_le16(header->max_entries_count);
136 void ext4_extent_header_set_max_entries_count(struct ext4_extent_header *header,
139 header->max_entries_count = to_le16(max_count);
142 uint16_t ext4_extent_header_get_depth(struct ext4_extent_header *header)
144 return to_le16(header->depth);
147 void ext4_extent_header_set_depth(struct ext4_extent_header *header,
150 header->depth = to_le16(depth);
153 uint32_t ext4_extent_header_get_generation(struct ext4_extent_header *header)
155 return to_le32(header->generation);
158 void ext4_extent_header_set_generation(struct ext4_extent_header *header,
161 header->generation = to_le32(generation);
164 /**@brief Binary search in extent index node.
165 * @param header Extent header of index node
166 * @param index Output value - found index will be set here
167 * @param iblock Logical block number to find in index node */
168 static void ext4_extent_binsearch_idx(struct ext4_extent_header *header,
169 struct ext4_extent_index **index,
172 struct ext4_extent_index *r;
173 struct ext4_extent_index *l;
174 struct ext4_extent_index *m;
176 uint16_t entries_count = ext4_extent_header_get_entries_count(header);
178 /* Initialize bounds */
179 l = EXT4_EXTENT_FIRST_INDEX(header) + 1;
180 r = EXT4_EXTENT_FIRST_INDEX(header) + entries_count - 1;
182 /* Do binary search */
185 uint32_t first_block = ext4_extent_index_get_first_block(m);
187 if (iblock < first_block)
193 /* Set output value */
197 /**@brief Binary search in extent leaf node.
198 * @param header Extent header of leaf node
199 * @param extent Output value - found extent will be set here,
200 * or NULL if node is empty
201 * @param iblock Logical block number to find in leaf node */
202 static void ext4_extent_binsearch(struct ext4_extent_header *header,
203 struct ext4_extent **extent, uint32_t iblock)
205 struct ext4_extent *r;
206 struct ext4_extent *l;
207 struct ext4_extent *m;
209 uint16_t entries_count = ext4_extent_header_get_entries_count(header);
211 if (entries_count == 0) {
212 /* this leaf is empty */
217 /* Initialize bounds */
218 l = EXT4_EXTENT_FIRST(header) + 1;
219 r = EXT4_EXTENT_FIRST(header) + entries_count - 1;
221 /* Do binary search */
224 uint32_t first_block = ext4_extent_get_first_block(m);
226 if (iblock < first_block)
232 /* Set output value */
236 int ext4_extent_find_block(struct ext4_inode_ref *inode_ref, uint32_t iblock,
240 /* Compute bound defined by i-node size */
241 uint64_t inode_size =
242 ext4_inode_get_size(&inode_ref->fs->sb, inode_ref->inode);
244 uint32_t block_size = ext4_sb_get_block_size(&inode_ref->fs->sb);
246 uint32_t last_idx = (inode_size - 1) / block_size;
248 /* Check if requested iblock is not over size of i-node */
249 if (iblock > last_idx) {
254 struct ext4_block block;
257 /* Walk through extent tree */
258 struct ext4_extent_header *header =
259 ext4_inode_get_extent_header(inode_ref->inode);
261 while (ext4_extent_header_get_depth(header) != 0) {
262 /* Search index in node */
263 struct ext4_extent_index *index;
264 ext4_extent_binsearch_idx(header, &index, iblock);
266 /* Load child node and set values for the next iteration */
267 uint64_t child = ext4_extent_index_get_leaf(index);
270 rc = ext4_block_set(inode_ref->fs->bdev, &block);
275 int rc = ext4_block_get(inode_ref->fs->bdev, &block, child);
279 header = (struct ext4_extent_header *)block.data;
282 /* Search extent in the leaf block */
283 struct ext4_extent *extent = NULL;
284 ext4_extent_binsearch(header, &extent, iblock);
286 /* Prevent empty leaf */
287 if (extent == NULL) {
290 /* Compute requested physical block address */
292 uint32_t first = ext4_extent_get_first_block(extent);
293 phys_block = ext4_extent_get_start(extent) + iblock - first;
295 *fblock = phys_block;
300 rc = ext4_block_set(inode_ref->fs->bdev, &block);
308 /**@brief Find extent for specified iblock.
309 * This function is used for finding block in the extent tree with
310 * saving the path through the tree for possible future modifications.
311 * @param inode_ref I-node to read extent tree from
312 * @param iblock Iblock to find extent for
313 * @param ret_path Output value for loaded path from extent tree
314 * @return Error code */
315 static int ext4_extent_find_extent(struct ext4_inode_ref *inode_ref,
317 struct ext4_extent_path **ret_path)
319 struct ext4_extent_header *eh =
320 ext4_inode_get_extent_header(inode_ref->inode);
322 uint16_t depth = ext4_extent_header_get_depth(eh);
324 struct ext4_extent_path *tmp_path;
326 /* Added 2 for possible tree growing */
327 tmp_path = malloc(sizeof(struct ext4_extent_path) * (depth + 2));
328 if (tmp_path == NULL)
331 /* Initialize structure for algorithm start */
332 tmp_path[0].block = inode_ref->block;
333 tmp_path[0].header = eh;
335 /* Walk through the extent tree */
338 while (ext4_extent_header_get_depth(eh) != 0) {
339 /* Search index in index node by iblock */
340 ext4_extent_binsearch_idx(tmp_path[pos].header,
341 &tmp_path[pos].index, iblock);
343 tmp_path[pos].depth = depth;
344 tmp_path[pos].extent = NULL;
346 ext4_assert(tmp_path[pos].index != 0);
348 /* Load information for the next iteration */
350 ext4_extent_index_get_leaf(tmp_path[pos].index);
352 struct ext4_block block;
353 rc = ext4_block_get(inode_ref->fs->bdev, &block, fblock);
359 eh = (struct ext4_extent_header *)block.data;
360 tmp_path[pos].block = block;
361 tmp_path[pos].header = eh;
364 tmp_path[pos].depth = 0;
365 tmp_path[pos].extent = NULL;
366 tmp_path[pos].index = NULL;
368 /* Find extent in the leaf node */
369 ext4_extent_binsearch(tmp_path[pos].header, &tmp_path[pos].extent,
371 *ret_path = tmp_path;
378 * From 1: 0 is a block with inode data
380 for (i = 1; i < tmp_path->depth; ++i) {
381 if (tmp_path[i].block.lb_id) {
382 int r = ext4_block_set(inode_ref->fs->bdev,
389 /* Destroy temporary data structure */
395 /**@brief Release extent and all data blocks covered by the extent.
396 * @param inode_ref I-node to release extent and block from
397 * @param extent Extent to release
398 * @return Error code */
399 static int ext4_extent_release(struct ext4_inode_ref *inode_ref,
400 struct ext4_extent *extent)
402 /* Compute number of the first physical block to release */
403 uint64_t start = ext4_extent_get_start(extent);
404 uint16_t block_count = ext4_extent_get_block_count(extent);
406 return ext4_balloc_free_blocks(inode_ref, start, block_count);
409 /** Recursively release the whole branch of the extent tree.
410 * For each entry of the node release the subbranch and finally release
411 * the node. In the leaf node all extents will be released.
412 * @param inode_ref I-node where the branch is released
413 * @param index Index in the non-leaf node to be released
414 * with the whole subtree
415 * @return Error code */
416 static int ext4_extent_release_branch(struct ext4_inode_ref *inode_ref,
417 struct ext4_extent_index *index)
419 uint32_t fblock = ext4_extent_index_get_leaf(index);
421 struct ext4_block block;
422 int rc = ext4_block_get(inode_ref->fs->bdev, &block, fblock);
426 struct ext4_extent_header *header = (void *)block.data;
428 if (ext4_extent_header_get_depth(header)) {
429 /* The node is non-leaf, do recursion */
430 struct ext4_extent_index *idx = EXT4_EXTENT_FIRST_INDEX(header);
432 /* Release all subbranches */
433 for (i = 0; i < ext4_extent_header_get_entries_count(header);
435 rc = ext4_extent_release_branch(inode_ref, idx);
440 /* Leaf node reached */
441 struct ext4_extent *ext = EXT4_EXTENT_FIRST(header);
443 /* Release all extents and stop recursion */
444 for (i = 0; i < ext4_extent_header_get_entries_count(header);
446 rc = ext4_extent_release(inode_ref, ext);
452 /* Release data block where the node was stored */
454 rc = ext4_block_set(inode_ref->fs->bdev, &block);
458 return ext4_balloc_free_block(inode_ref, fblock);
461 int ext4_extent_release_blocks_from(struct ext4_inode_ref *inode_ref,
462 uint32_t iblock_from)
464 /* Find the first extent to modify */
465 struct ext4_extent_path *path;
467 int rc = ext4_extent_find_extent(inode_ref, iblock_from, &path);
471 /* Jump to last item of the path (extent) */
472 struct ext4_extent_path *path_ptr = path;
473 while (path_ptr->depth != 0)
476 ext4_assert(path_ptr->extent != NULL);
478 /* First extent maybe released partially */
479 uint32_t first_iblock = ext4_extent_get_first_block(path_ptr->extent);
480 uint32_t first_fblock = ext4_extent_get_start(path_ptr->extent) +
481 iblock_from - first_iblock;
483 uint16_t block_count = ext4_extent_get_block_count(path_ptr->extent);
485 uint16_t delete_count =
487 (ext4_extent_get_start(path_ptr->extent) - first_fblock);
489 /* Release all blocks */
490 rc = ext4_balloc_free_blocks(inode_ref, first_fblock, delete_count);
494 /* Correct counter */
495 block_count -= delete_count;
496 ext4_extent_set_block_count(path_ptr->extent, block_count);
498 /* Initialize the following loop */
500 ext4_extent_header_get_entries_count(path_ptr->header);
501 struct ext4_extent *tmp_ext = path_ptr->extent + 1;
502 struct ext4_extent *stop_ext =
503 EXT4_EXTENT_FIRST(path_ptr->header) + entries;
505 /* If first extent empty, release it */
506 if (block_count == 0)
509 /* Release all successors of the first extent in the same node */
510 while (tmp_ext < stop_ext) {
511 first_fblock = ext4_extent_get_start(tmp_ext);
512 delete_count = ext4_extent_get_block_count(tmp_ext);
514 rc = ext4_balloc_free_blocks(inode_ref, first_fblock,
523 ext4_extent_header_set_entries_count(path_ptr->header, entries);
524 path_ptr->block.dirty = true;
526 /* If leaf node is empty, parent entry must be modified */
527 bool remove_parent_record = false;
529 /* Don't release root block (including inode data) !!! */
530 if ((path_ptr != path) && (entries == 0)) {
531 rc = ext4_balloc_free_block(inode_ref, path_ptr->block.lb_id);
535 remove_parent_record = true;
538 /* Jump to the parent */
541 /* Release all successors in all tree levels */
542 while (path_ptr >= path) {
544 ext4_extent_header_get_entries_count(path_ptr->header);
545 struct ext4_extent_index *index = path_ptr->index + 1;
546 struct ext4_extent_index *stop =
547 EXT4_EXTENT_FIRST_INDEX(path_ptr->header) + entries;
549 /* Correct entries count because of changes in the previous
551 if (remove_parent_record)
554 /* Iterate over all entries and release the whole subtrees */
555 while (index < stop) {
556 rc = ext4_extent_release_branch(inode_ref, index);
564 ext4_extent_header_set_entries_count(path_ptr->header, entries);
565 path_ptr->block.dirty = true;
567 /* Free the node if it is empty */
568 if ((entries == 0) && (path_ptr != path)) {
569 rc = ext4_balloc_free_block(inode_ref,
570 path_ptr->block.lb_id);
574 /* Mark parent to be checked */
575 remove_parent_record = true;
577 remove_parent_record = false;
583 ext4_extent_header_set_depth(path->header, 0);
588 * starting from 1: 0 is a block with inode data
590 for (i = 1; i <= path->depth; ++i) {
591 if (path[i].block.lb_id) {
593 ext4_block_set(inode_ref->fs->bdev, &path[i].block);
599 /* Destroy temporary data structure */
605 /**@brief Append new extent to the i-node and do some splitting if necessary.
606 * @param inode_ref I-node to append extent to
607 * @param path Path in the extent tree for possible splitting
608 * @param last_path_item Input/output parameter for pointer to the last
609 * valid item in the extent tree path
610 * @param iblock Logical index of block to append extent for
611 * @return Error code */
612 static int ext4_extent_append_extent(struct ext4_inode_ref *inode_ref,
613 struct ext4_extent_path *path,
616 struct ext4_extent_path *path_ptr = path + path->depth;
618 uint32_t block_size = ext4_sb_get_block_size(&inode_ref->fs->sb);
620 /* Start splitting */
621 while (path_ptr > path) {
623 ext4_extent_header_get_entries_count(path_ptr->header);
625 ext4_extent_header_get_max_entries_count(path_ptr->header);
627 if (entries == limit) {
628 /* Full node - allocate block for new one */
630 int rc = ext4_balloc_alloc_block(inode_ref, &fblock);
634 struct ext4_block block;
636 ext4_block_get(inode_ref->fs->bdev, &block, fblock);
638 ext4_balloc_free_block(inode_ref, fblock);
642 /* Put back not modified old block */
643 rc = ext4_block_set(inode_ref->fs->bdev,
646 ext4_balloc_free_block(inode_ref, fblock);
650 /* Initialize newly allocated block and remember it */
651 memset(block.data, 0, block_size);
652 path_ptr->block = block;
654 /* Update pointers in extent path structure */
655 path_ptr->header = (void *)block.data;
656 if (path_ptr->depth) {
658 EXT4_EXTENT_FIRST_INDEX(path_ptr->header);
659 ext4_extent_index_set_first_block(
660 path_ptr->index, iblock);
661 ext4_extent_index_set_leaf(
663 (path_ptr + 1)->block.lb_id);
664 limit = (block_size -
665 sizeof(struct ext4_extent_header)) /
666 sizeof(struct ext4_extent_index);
669 EXT4_EXTENT_FIRST(path_ptr->header);
670 ext4_extent_set_first_block(path_ptr->extent,
672 limit = (block_size -
673 sizeof(struct ext4_extent_header)) /
674 sizeof(struct ext4_extent);
677 /* Initialize on-disk structure (header) */
678 ext4_extent_header_set_entries_count(path_ptr->header,
680 ext4_extent_header_set_max_entries_count(
681 path_ptr->header, limit);
682 ext4_extent_header_set_magic(path_ptr->header,
684 ext4_extent_header_set_depth(path_ptr->header,
686 ext4_extent_header_set_generation(path_ptr->header, 0);
688 path_ptr->block.dirty = true;
690 /* Jump to the preceding item */
693 /* Node with free space */
694 if (path_ptr->depth) {
696 EXT4_EXTENT_FIRST_INDEX(path_ptr->header) +
698 ext4_extent_index_set_first_block(
699 path_ptr->index, iblock);
700 ext4_extent_index_set_leaf(
702 (path_ptr + 1)->block.lb_id);
705 EXT4_EXTENT_FIRST(path_ptr->header) +
707 ext4_extent_set_first_block(path_ptr->extent,
711 ext4_extent_header_set_entries_count(path_ptr->header,
713 path_ptr->block.dirty = true;
715 /* No more splitting needed */
720 ext4_assert(path_ptr == path);
722 /* Should be the root split too? */
724 uint16_t entries = ext4_extent_header_get_entries_count(path->header);
725 uint16_t limit = ext4_extent_header_get_max_entries_count(path->header);
727 if (entries == limit) {
729 int rc = ext4_balloc_alloc_block(inode_ref, &new_fblock);
733 struct ext4_block block;
734 rc = ext4_block_get(inode_ref->fs->bdev, &block, new_fblock);
738 /* Initialize newly allocated block */
739 memset(block.data, 0, block_size);
741 /* Move data from root to the new block */
742 memcpy(block.data, inode_ref->inode->blocks,
743 EXT4_INODE_BLOCKS * sizeof(uint32_t));
745 /* Data block is initialized */
747 struct ext4_block *root_block = &path->block;
748 uint16_t root_depth = path->depth;
749 struct ext4_extent_header *root_header = path->header;
751 /* Make space for tree growing */
752 struct ext4_extent_path *new_root = path;
753 struct ext4_extent_path *old_root = path + 1;
756 sizeof(struct ext4_extent_path) * (path->depth + 1);
757 memmove(old_root, new_root, nbytes);
758 memset(new_root, 0, sizeof(struct ext4_extent_path));
760 /* Update old root structure */
761 old_root->block = block;
762 old_root->header = (struct ext4_extent_header *)block.data;
764 /* Add new entry and update limit for entries */
765 if (old_root->depth) {
767 (block_size - sizeof(struct ext4_extent_header)) /
768 sizeof(struct ext4_extent_index);
770 EXT4_EXTENT_FIRST_INDEX(old_root->header) + entries;
771 ext4_extent_index_set_first_block(old_root->index,
773 ext4_extent_index_set_leaf(old_root->index,
774 (old_root + 1)->block.lb_id);
775 old_root->extent = NULL;
778 (block_size - sizeof(struct ext4_extent_header)) /
779 sizeof(struct ext4_extent);
781 EXT4_EXTENT_FIRST(old_root->header) + entries;
782 ext4_extent_set_first_block(old_root->extent, iblock);
783 old_root->index = NULL;
786 ext4_extent_header_set_entries_count(old_root->header,
788 ext4_extent_header_set_max_entries_count(old_root->header,
791 old_root->block.dirty = true;
793 /* Re-initialize new root metadata */
794 new_root->depth = root_depth + 1;
795 new_root->block = *root_block;
796 new_root->header = root_header;
797 new_root->extent = NULL;
798 new_root->index = EXT4_EXTENT_FIRST_INDEX(new_root->header);
800 ext4_extent_header_set_depth(new_root->header, new_root->depth);
802 /* Create new entry in root */
803 ext4_extent_header_set_entries_count(new_root->header, 1);
804 ext4_extent_index_set_first_block(new_root->index, 0);
805 ext4_extent_index_set_leaf(new_root->index, new_fblock);
807 new_root->block.dirty = true;
811 EXT4_EXTENT_FIRST_INDEX(path->header) + entries;
812 ext4_extent_index_set_first_block(path->index, iblock);
813 ext4_extent_index_set_leaf(path->index,
814 (path + 1)->block.lb_id);
817 EXT4_EXTENT_FIRST(path->header) + entries;
818 ext4_extent_set_first_block(path->extent, iblock);
821 ext4_extent_header_set_entries_count(path->header, entries + 1);
822 path->block.dirty = true;
828 int ext4_extent_append_block(struct ext4_inode_ref *inode_ref, uint32_t *iblock,
829 uint32_t *fblock, bool update_size)
832 struct ext4_sblock *sb = &inode_ref->fs->sb;
833 uint64_t inode_size = ext4_inode_get_size(sb, inode_ref->inode);
834 uint32_t block_size = ext4_sb_get_block_size(sb);
836 /* Calculate number of new logical block */
837 uint32_t new_block_idx = 0;
838 if (inode_size > 0) {
839 if ((inode_size % block_size) != 0)
840 inode_size += block_size - (inode_size % block_size);
842 new_block_idx = inode_size / block_size;
845 /* Load the nearest leaf (with extent) */
846 struct ext4_extent_path *path;
847 int rc = ext4_extent_find_extent(inode_ref, new_block_idx, &path);
851 /* Jump to last item of the path (extent) */
852 struct ext4_extent_path *path_ptr = path;
853 while (path_ptr->depth != 0)
856 /* Add new extent to the node if not present */
857 if (path_ptr->extent == NULL)
860 uint16_t block_count = ext4_extent_get_block_count(path_ptr->extent);
861 uint16_t block_limit = (1 << 15);
863 uint32_t phys_block = 0;
864 if (block_count < block_limit) {
865 /* There is space for new block in the extent */
866 if (block_count == 0) {
867 /* Existing extent is empty */
868 rc = ext4_balloc_alloc_block(inode_ref, &phys_block);
872 /* Initialize extent */
873 ext4_extent_set_first_block(path_ptr->extent,
875 ext4_extent_set_start(path_ptr->extent, phys_block);
876 ext4_extent_set_block_count(path_ptr->extent, 1);
880 ext4_inode_set_size(inode_ref->inode,
881 inode_size + block_size);
882 inode_ref->dirty = true;
885 path_ptr->block.dirty = true;
889 /* Existing extent contains some blocks */
890 phys_block = ext4_extent_get_start(path_ptr->extent);
892 ext4_extent_get_block_count(path_ptr->extent);
894 /* Check if the following block is free for allocation
897 rc = ext4_balloc_try_alloc_block(inode_ref, phys_block,
903 /* Target is not free, new block must be
904 * appended to new extent
910 ext4_extent_set_block_count(path_ptr->extent,
915 ext4_inode_set_size(inode_ref->inode,
916 inode_size + block_size);
917 inode_ref->dirty = true;
920 path_ptr->block.dirty = true;
927 /* Append new extent to the tree */
930 /* Allocate new data block */
931 rc = ext4_balloc_alloc_block(inode_ref, &phys_block);
935 /* Append extent for new block (includes tree splitting if needed) */
936 rc = ext4_extent_append_extent(inode_ref, path, new_block_idx);
938 ext4_balloc_free_block(inode_ref, phys_block);
942 uint32_t tree_depth = ext4_extent_header_get_depth(path->header);
943 path_ptr = path + tree_depth;
945 /* Initialize newly created extent */
946 ext4_extent_set_block_count(path_ptr->extent, 1);
947 ext4_extent_set_first_block(path_ptr->extent, new_block_idx);
948 ext4_extent_set_start(path_ptr->extent, phys_block);
952 ext4_inode_set_size(inode_ref->inode, inode_size + block_size);
953 inode_ref->dirty = true;
956 path_ptr->block.dirty = true;
959 /* Set return values */
960 *iblock = new_block_idx;
961 *fblock = phys_block;
965 * starting from 1: 0 is a block with inode data
967 for (i = 1; i <= path->depth; ++i) {
968 if (path[i].block.lb_id) {
970 ext4_block_set(inode_ref->fs->bdev, &path[i].block);
976 /* Destroy temporary data structure */