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 #if !CONFIG_EXTENT_FULL
54 uint32_t ext4_extent_get_first_block(struct ext4_extent *extent)
56 return to_le32(extent->first_block);
59 void ext4_extent_set_first_block(struct ext4_extent *extent, uint32_t iblock)
61 extent->first_block = to_le32(iblock);
64 uint16_t ext4_extent_get_block_count(struct ext4_extent *extent)
66 if (EXT4_EXT_IS_UNWRITTEN(extent))
67 return EXT4_EXT_GET_LEN_UNWRITTEN(extent);
69 return EXT4_EXT_GET_LEN(extent);
72 void ext4_extent_set_block_count(struct ext4_extent *extent, uint16_t count,
75 EXT4_EXT_SET_LEN(extent, count);
77 EXT4_EXT_SET_UNWRITTEN(extent);
80 uint64_t ext4_extent_get_start(struct ext4_extent *extent)
82 return ((uint64_t)to_le16(extent->start_hi)) << 32 |
83 ((uint64_t)to_le32(extent->start_lo));
86 void ext4_extent_set_start(struct ext4_extent *extent, uint64_t fblock)
88 extent->start_lo = to_le32((fblock << 32) >> 32);
89 extent->start_hi = to_le16((uint16_t)(fblock >> 32));
92 uint32_t ext4_extent_index_get_first_block(struct ext4_extent_index *index)
94 return to_le32(index->first_block);
97 void ext4_extent_index_set_first_block(struct ext4_extent_index *index,
100 index->first_block = to_le32(iblock);
103 uint64_t ext4_extent_index_get_leaf(struct ext4_extent_index *index)
105 return ((uint64_t)to_le16(index->leaf_hi)) << 32 |
106 ((uint64_t)to_le32(index->leaf_lo));
109 void ext4_extent_index_set_leaf(struct ext4_extent_index *index,
112 index->leaf_lo = to_le32((fblock << 32) >> 32);
113 index->leaf_hi = to_le16((uint16_t)(fblock >> 32));
116 uint16_t ext4_extent_header_get_magic(struct ext4_extent_header *header)
118 return to_le16(header->magic);
121 void ext4_extent_header_set_magic(struct ext4_extent_header *header,
124 header->magic = to_le16(magic);
127 uint16_t ext4_extent_header_get_entries_count(struct ext4_extent_header *header)
129 return to_le16(header->entries_count);
132 void ext4_extent_header_set_entries_count(struct ext4_extent_header *header,
135 header->entries_count = to_le16(count);
139 ext4_extent_header_get_max_entries_count(struct ext4_extent_header *header)
141 return to_le16(header->max_entries_count);
144 void ext4_extent_header_set_max_entries_count(struct ext4_extent_header *header,
147 header->max_entries_count = to_le16(max_count);
150 uint16_t ext4_extent_header_get_depth(struct ext4_extent_header *header)
152 return to_le16(header->depth);
155 void ext4_extent_header_set_depth(struct ext4_extent_header *header,
158 header->depth = to_le16(depth);
161 uint32_t ext4_extent_header_get_generation(struct ext4_extent_header *header)
163 return to_le32(header->generation);
166 void ext4_extent_header_set_generation(struct ext4_extent_header *header,
169 header->generation = to_le32(generation);
172 /**@brief Binary search in extent index node.
173 * @param header Extent header of index node
174 * @param index Output value - found index will be set here
175 * @param iblock Logical block number to find in index node */
176 static void ext4_extent_binsearch_idx(struct ext4_extent_header *header,
177 struct ext4_extent_index **index,
180 struct ext4_extent_index *r;
181 struct ext4_extent_index *l;
182 struct ext4_extent_index *m;
184 uint16_t entries_count = ext4_extent_header_get_entries_count(header);
186 /* Initialize bounds */
187 l = EXT4_EXTENT_FIRST_INDEX(header) + 1;
188 r = EXT4_EXTENT_FIRST_INDEX(header) + entries_count - 1;
190 /* Do binary search */
193 uint32_t first_block = ext4_extent_index_get_first_block(m);
195 if (iblock < first_block)
201 /* Set output value */
205 /**@brief Binary search in extent leaf node.
206 * @param header Extent header of leaf node
207 * @param extent Output value - found extent will be set here,
208 * or NULL if node is empty
209 * @param iblock Logical block number to find in leaf node */
210 static void ext4_extent_binsearch(struct ext4_extent_header *header,
211 struct ext4_extent **extent, uint32_t iblock)
213 struct ext4_extent *r;
214 struct ext4_extent *l;
215 struct ext4_extent *m;
217 uint16_t entries_count = ext4_extent_header_get_entries_count(header);
219 if (entries_count == 0) {
220 /* this leaf is empty */
225 /* Initialize bounds */
226 l = EXT4_EXTENT_FIRST(header) + 1;
227 r = EXT4_EXTENT_FIRST(header) + entries_count - 1;
229 /* Do binary search */
232 uint32_t first_block = ext4_extent_get_first_block(m);
234 if (iblock < first_block)
240 /* Set output value */
244 int ext4_extent_find_block(struct ext4_inode_ref *inode_ref, uint32_t iblock,
248 /* Compute bound defined by i-node size */
249 uint64_t inode_size =
250 ext4_inode_get_size(&inode_ref->fs->sb, inode_ref->inode);
252 uint32_t block_size = ext4_sb_get_block_size(&inode_ref->fs->sb);
254 uint32_t last_idx = (inode_size - 1) / block_size;
256 /* Check if requested iblock is not over size of i-node */
257 if (iblock > last_idx) {
262 struct ext4_block block;
265 /* Walk through extent tree */
266 struct ext4_extent_header *header =
267 ext4_inode_get_extent_header(inode_ref->inode);
269 while (ext4_extent_header_get_depth(header) != 0) {
270 /* Search index in node */
271 struct ext4_extent_index *index;
272 ext4_extent_binsearch_idx(header, &index, iblock);
274 /* Load child node and set values for the next iteration */
275 uint64_t child = ext4_extent_index_get_leaf(index);
278 rc = ext4_block_set(inode_ref->fs->bdev, &block);
283 int rc = ext4_block_get(inode_ref->fs->bdev, &block, child);
287 header = (struct ext4_extent_header *)block.data;
290 /* Search extent in the leaf block */
291 struct ext4_extent *extent = NULL;
292 ext4_extent_binsearch(header, &extent, iblock);
294 /* Prevent empty leaf */
295 if (extent == NULL) {
298 /* Compute requested physical block address */
300 uint32_t first = ext4_extent_get_first_block(extent);
301 phys_block = ext4_extent_get_start(extent) + iblock - first;
303 *fblock = phys_block;
308 rc = ext4_block_set(inode_ref->fs->bdev, &block);
316 /**@brief Find extent for specified iblock.
317 * This function is used for finding block in the extent tree with
318 * saving the path through the tree for possible future modifications.
319 * @param inode_ref I-node to read extent tree from
320 * @param iblock Iblock to find extent for
321 * @param ret_path Output value for loaded path from extent tree
322 * @return Error code */
323 static int ext4_extent_find_extent(struct ext4_inode_ref *inode_ref,
325 struct ext4_extent_path **ret_path)
327 struct ext4_extent_header *eh =
328 ext4_inode_get_extent_header(inode_ref->inode);
330 uint16_t depth = ext4_extent_header_get_depth(eh);
332 struct ext4_extent_path *tmp_path;
334 /* Added 2 for possible tree growing */
335 tmp_path = malloc(sizeof(struct ext4_extent_path) * (depth + 2));
336 if (tmp_path == NULL)
339 /* Initialize structure for algorithm start */
340 tmp_path[0].block = inode_ref->block;
341 tmp_path[0].header = eh;
343 /* Walk through the extent tree */
346 while (ext4_extent_header_get_depth(eh) != 0) {
347 /* Search index in index node by iblock */
348 ext4_extent_binsearch_idx(tmp_path[pos].header,
349 &tmp_path[pos].index, iblock);
351 tmp_path[pos].depth = depth;
352 tmp_path[pos].extent = NULL;
354 ext4_assert(tmp_path[pos].index != 0);
356 /* Load information for the next iteration */
358 ext4_extent_index_get_leaf(tmp_path[pos].index);
360 struct ext4_block block;
361 rc = ext4_block_get(inode_ref->fs->bdev, &block, fblock);
367 eh = (struct ext4_extent_header *)block.data;
368 tmp_path[pos].block = block;
369 tmp_path[pos].header = eh;
372 tmp_path[pos].depth = 0;
373 tmp_path[pos].extent = NULL;
374 tmp_path[pos].index = NULL;
376 /* Find extent in the leaf node */
377 ext4_extent_binsearch(tmp_path[pos].header, &tmp_path[pos].extent,
379 *ret_path = tmp_path;
386 * From 1: 0 is a block with inode data
388 for (i = 1; i < tmp_path->depth; ++i) {
389 if (tmp_path[i].block.lb_id) {
390 int r = ext4_block_set(inode_ref->fs->bdev,
397 /* Destroy temporary data structure */
403 /**@brief Release extent and all data blocks covered by the extent.
404 * @param inode_ref I-node to release extent and block from
405 * @param extent Extent to release
406 * @return Error code */
407 static int ext4_extent_release(struct ext4_inode_ref *inode_ref,
408 struct ext4_extent *extent)
410 /* Compute number of the first physical block to release */
411 uint64_t start = ext4_extent_get_start(extent);
412 uint16_t block_count = ext4_extent_get_block_count(extent);
414 return ext4_balloc_free_blocks(inode_ref, start, block_count);
417 /** Recursively release the whole branch of the extent tree.
418 * For each entry of the node release the subbranch and finally release
419 * the node. In the leaf node all extents will be released.
420 * @param inode_ref I-node where the branch is released
421 * @param index Index in the non-leaf node to be released
422 * with the whole subtree
423 * @return Error code */
424 static int ext4_extent_release_branch(struct ext4_inode_ref *inode_ref,
425 struct ext4_extent_index *index)
427 uint32_t fblock = ext4_extent_index_get_leaf(index);
429 struct ext4_block block;
430 int rc = ext4_block_get(inode_ref->fs->bdev, &block, fblock);
434 struct ext4_extent_header *header = (void *)block.data;
436 if (ext4_extent_header_get_depth(header)) {
437 /* The node is non-leaf, do recursion */
438 struct ext4_extent_index *idx = EXT4_EXTENT_FIRST_INDEX(header);
440 /* Release all subbranches */
441 for (i = 0; i < ext4_extent_header_get_entries_count(header);
443 rc = ext4_extent_release_branch(inode_ref, idx);
448 /* Leaf node reached */
449 struct ext4_extent *ext = EXT4_EXTENT_FIRST(header);
451 /* Release all extents and stop recursion */
452 for (i = 0; i < ext4_extent_header_get_entries_count(header);
454 rc = ext4_extent_release(inode_ref, ext);
460 /* Release data block where the node was stored */
462 rc = ext4_block_set(inode_ref->fs->bdev, &block);
466 return ext4_balloc_free_block(inode_ref, fblock);
469 int ext4_extent_release_blocks_from(struct ext4_inode_ref *inode_ref,
470 uint32_t iblock_from)
472 /* Find the first extent to modify */
473 struct ext4_extent_path *path;
475 int rc = ext4_extent_find_extent(inode_ref, iblock_from, &path);
479 /* Jump to last item of the path (extent) */
480 struct ext4_extent_path *path_ptr = path;
481 while (path_ptr->depth != 0)
484 ext4_assert(path_ptr->extent != NULL);
486 /* First extent maybe released partially */
487 uint32_t first_iblock = ext4_extent_get_first_block(path_ptr->extent);
488 uint32_t first_fblock = ext4_extent_get_start(path_ptr->extent) +
489 iblock_from - first_iblock;
491 uint16_t block_count = ext4_extent_get_block_count(path_ptr->extent);
493 uint16_t delete_count =
495 (ext4_extent_get_start(path_ptr->extent) - first_fblock);
497 /* Release all blocks */
498 rc = ext4_balloc_free_blocks(inode_ref, first_fblock, delete_count);
502 /* Correct counter */
503 block_count -= delete_count;
504 ext4_extent_set_block_count(path_ptr->extent, block_count,
505 EXT4_EXT_IS_UNWRITTEN(path_ptr->extent));
507 /* Initialize the following loop */
509 ext4_extent_header_get_entries_count(path_ptr->header);
510 struct ext4_extent *tmp_ext = path_ptr->extent + 1;
511 struct ext4_extent *stop_ext =
512 EXT4_EXTENT_FIRST(path_ptr->header) + entries;
514 /* If first extent empty, release it */
515 if (block_count == 0)
518 /* Release all successors of the first extent in the same node */
519 while (tmp_ext < stop_ext) {
520 first_fblock = ext4_extent_get_start(tmp_ext);
521 delete_count = ext4_extent_get_block_count(tmp_ext);
523 rc = ext4_balloc_free_blocks(inode_ref, first_fblock,
532 ext4_extent_header_set_entries_count(path_ptr->header, entries);
533 path_ptr->block.dirty = true;
535 /* If leaf node is empty, parent entry must be modified */
536 bool remove_parent_record = false;
538 /* Don't release root block (including inode data) !!! */
539 if ((path_ptr != path) && (entries == 0)) {
540 rc = ext4_balloc_free_block(inode_ref, path_ptr->block.lb_id);
544 remove_parent_record = true;
547 /* Jump to the parent */
550 /* Release all successors in all tree levels */
551 while (path_ptr >= path) {
553 ext4_extent_header_get_entries_count(path_ptr->header);
554 struct ext4_extent_index *index = path_ptr->index + 1;
555 struct ext4_extent_index *stop =
556 EXT4_EXTENT_FIRST_INDEX(path_ptr->header) + entries;
558 /* Correct entries count because of changes in the previous
560 if (remove_parent_record)
563 /* Iterate over all entries and release the whole subtrees */
564 while (index < stop) {
565 rc = ext4_extent_release_branch(inode_ref, index);
573 ext4_extent_header_set_entries_count(path_ptr->header, entries);
574 path_ptr->block.dirty = true;
576 /* Free the node if it is empty */
577 if ((entries == 0) && (path_ptr != path)) {
578 rc = ext4_balloc_free_block(inode_ref,
579 path_ptr->block.lb_id);
583 /* Mark parent to be checked */
584 remove_parent_record = true;
586 remove_parent_record = false;
592 ext4_extent_header_set_depth(path->header, 0);
597 * starting from 1: 0 is a block with inode data
599 for (i = 1; i <= path->depth; ++i) {
600 if (path[i].block.lb_id) {
602 ext4_block_set(inode_ref->fs->bdev, &path[i].block);
608 /* Destroy temporary data structure */
614 /**@brief Append new extent to the i-node and do some splitting if necessary.
615 * @param inode_ref I-node to append extent to
616 * @param path Path in the extent tree for possible splitting
617 * @param last_path_item Input/output parameter for pointer to the last
618 * valid item in the extent tree path
619 * @param iblock Logical index of block to append extent for
620 * @return Error code */
621 static int ext4_extent_append_extent(struct ext4_inode_ref *inode_ref,
622 struct ext4_extent_path *path,
625 struct ext4_extent_path *path_ptr = path + path->depth;
627 uint32_t block_size = ext4_sb_get_block_size(&inode_ref->fs->sb);
629 /* Start splitting */
630 while (path_ptr > path) {
632 ext4_extent_header_get_entries_count(path_ptr->header);
634 ext4_extent_header_get_max_entries_count(path_ptr->header);
636 if (entries == limit) {
637 /* Full node - allocate block for new one */
639 int rc = ext4_balloc_alloc_block(inode_ref, &fblock);
643 struct ext4_block block;
645 ext4_block_get(inode_ref->fs->bdev, &block, fblock);
647 ext4_balloc_free_block(inode_ref, fblock);
651 /* Put back not modified old block */
652 rc = ext4_block_set(inode_ref->fs->bdev,
655 ext4_balloc_free_block(inode_ref, fblock);
659 /* Initialize newly allocated block and remember it */
660 memset(block.data, 0, block_size);
661 path_ptr->block = block;
663 /* Update pointers in extent path structure */
664 path_ptr->header = (void *)block.data;
665 if (path_ptr->depth) {
667 EXT4_EXTENT_FIRST_INDEX(path_ptr->header);
668 ext4_extent_index_set_first_block(
669 path_ptr->index, iblock);
670 ext4_extent_index_set_leaf(
672 (path_ptr + 1)->block.lb_id);
673 limit = (block_size -
674 sizeof(struct ext4_extent_header)) /
675 sizeof(struct ext4_extent_index);
678 EXT4_EXTENT_FIRST(path_ptr->header);
679 ext4_extent_set_first_block(path_ptr->extent,
681 limit = (block_size -
682 sizeof(struct ext4_extent_header)) /
683 sizeof(struct ext4_extent);
686 /* Initialize on-disk structure (header) */
687 ext4_extent_header_set_entries_count(path_ptr->header,
689 ext4_extent_header_set_max_entries_count(
690 path_ptr->header, limit);
691 ext4_extent_header_set_magic(path_ptr->header,
693 ext4_extent_header_set_depth(path_ptr->header,
695 ext4_extent_header_set_generation(path_ptr->header, 0);
697 path_ptr->block.dirty = true;
699 /* Jump to the preceding item */
702 /* Node with free space */
703 if (path_ptr->depth) {
705 EXT4_EXTENT_FIRST_INDEX(path_ptr->header) +
707 ext4_extent_index_set_first_block(
708 path_ptr->index, iblock);
709 ext4_extent_index_set_leaf(
711 (path_ptr + 1)->block.lb_id);
714 EXT4_EXTENT_FIRST(path_ptr->header) +
716 ext4_extent_set_first_block(path_ptr->extent,
720 ext4_extent_header_set_entries_count(path_ptr->header,
722 path_ptr->block.dirty = true;
724 /* No more splitting needed */
729 ext4_assert(path_ptr == path);
731 /* Should be the root split too? */
733 uint16_t entries = ext4_extent_header_get_entries_count(path->header);
734 uint16_t limit = ext4_extent_header_get_max_entries_count(path->header);
736 if (entries == limit) {
738 int rc = ext4_balloc_alloc_block(inode_ref, &new_fblock);
742 struct ext4_block block;
743 rc = ext4_block_get(inode_ref->fs->bdev, &block, new_fblock);
747 /* Initialize newly allocated block */
748 memset(block.data, 0, block_size);
750 /* Move data from root to the new block */
751 memcpy(block.data, inode_ref->inode->blocks,
752 EXT4_INODE_BLOCKS * sizeof(uint32_t));
754 /* Data block is initialized */
756 struct ext4_block *root_block = &path->block;
757 uint16_t root_depth = path->depth;
758 struct ext4_extent_header *root_header = path->header;
760 /* Make space for tree growing */
761 struct ext4_extent_path *new_root = path;
762 struct ext4_extent_path *old_root = path + 1;
765 sizeof(struct ext4_extent_path) * (path->depth + 1);
766 memmove(old_root, new_root, nbytes);
767 memset(new_root, 0, sizeof(struct ext4_extent_path));
769 /* Update old root structure */
770 old_root->block = block;
771 old_root->header = (struct ext4_extent_header *)block.data;
773 /* Add new entry and update limit for entries */
774 if (old_root->depth) {
776 (block_size - sizeof(struct ext4_extent_header)) /
777 sizeof(struct ext4_extent_index);
779 EXT4_EXTENT_FIRST_INDEX(old_root->header) + entries;
780 ext4_extent_index_set_first_block(old_root->index,
782 ext4_extent_index_set_leaf(old_root->index,
783 (old_root + 1)->block.lb_id);
784 old_root->extent = NULL;
787 (block_size - sizeof(struct ext4_extent_header)) /
788 sizeof(struct ext4_extent);
790 EXT4_EXTENT_FIRST(old_root->header) + entries;
791 ext4_extent_set_first_block(old_root->extent, iblock);
792 old_root->index = NULL;
795 ext4_extent_header_set_entries_count(old_root->header,
797 ext4_extent_header_set_max_entries_count(old_root->header,
800 old_root->block.dirty = true;
802 /* Re-initialize new root metadata */
803 new_root->depth = root_depth + 1;
804 new_root->block = *root_block;
805 new_root->header = root_header;
806 new_root->extent = NULL;
807 new_root->index = EXT4_EXTENT_FIRST_INDEX(new_root->header);
809 ext4_extent_header_set_depth(new_root->header, new_root->depth);
811 /* Create new entry in root */
812 ext4_extent_header_set_entries_count(new_root->header, 1);
813 ext4_extent_index_set_first_block(new_root->index, 0);
814 ext4_extent_index_set_leaf(new_root->index, new_fblock);
816 new_root->block.dirty = true;
820 EXT4_EXTENT_FIRST_INDEX(path->header) + entries;
821 ext4_extent_index_set_first_block(path->index, iblock);
822 ext4_extent_index_set_leaf(path->index,
823 (path + 1)->block.lb_id);
826 EXT4_EXTENT_FIRST(path->header) + entries;
827 ext4_extent_set_first_block(path->extent, iblock);
830 ext4_extent_header_set_entries_count(path->header, entries + 1);
831 path->block.dirty = true;
837 int ext4_extent_append_block(struct ext4_inode_ref *inode_ref, uint32_t *iblock,
838 uint32_t *fblock, bool update_size)
841 struct ext4_sblock *sb = &inode_ref->fs->sb;
842 uint64_t inode_size = ext4_inode_get_size(sb, inode_ref->inode);
843 uint32_t block_size = ext4_sb_get_block_size(sb);
845 /* Calculate number of new logical block */
846 uint32_t new_block_idx = 0;
847 if (inode_size > 0) {
848 if ((inode_size % block_size) != 0)
849 inode_size += block_size - (inode_size % block_size);
851 new_block_idx = inode_size / block_size;
854 /* Load the nearest leaf (with extent) */
855 struct ext4_extent_path *path;
856 int rc = ext4_extent_find_extent(inode_ref, new_block_idx, &path);
860 /* Jump to last item of the path (extent) */
861 struct ext4_extent_path *path_ptr = path;
862 while (path_ptr->depth != 0)
865 /* Add new extent to the node if not present */
866 if (path_ptr->extent == NULL)
869 uint16_t block_count = ext4_extent_get_block_count(path_ptr->extent);
870 uint16_t block_limit = (1 << 15);
872 uint32_t phys_block = 0;
873 if (block_count < block_limit) {
874 /* There is space for new block in the extent */
875 if (block_count == 0) {
876 /* Existing extent is empty */
877 rc = ext4_balloc_alloc_block(inode_ref, &phys_block);
881 /* Initialize extent */
882 ext4_extent_set_first_block(path_ptr->extent,
884 ext4_extent_set_start(path_ptr->extent, phys_block);
885 ext4_extent_set_block_count(path_ptr->extent, 1,
890 ext4_inode_set_size(inode_ref->inode,
891 inode_size + block_size);
892 inode_ref->dirty = true;
895 path_ptr->block.dirty = true;
899 /* Existing extent contains some blocks */
900 phys_block = ext4_extent_get_start(path_ptr->extent);
902 ext4_extent_get_block_count(path_ptr->extent);
904 /* Check if the following block is free for allocation
907 rc = ext4_balloc_try_alloc_block(inode_ref, phys_block,
913 /* Target is not free, new block must be
914 * appended to new extent
920 ext4_extent_set_block_count(path_ptr->extent,
926 ext4_inode_set_size(inode_ref->inode,
927 inode_size + block_size);
928 inode_ref->dirty = true;
931 path_ptr->block.dirty = true;
938 /* Append new extent to the tree */
941 /* Allocate new data block */
942 rc = ext4_balloc_alloc_block(inode_ref, &phys_block);
946 /* Append extent for new block (includes tree splitting if needed) */
947 rc = ext4_extent_append_extent(inode_ref, path, new_block_idx);
949 ext4_balloc_free_block(inode_ref, phys_block);
953 uint32_t tree_depth = ext4_extent_header_get_depth(path->header);
954 path_ptr = path + tree_depth;
956 /* Initialize newly created extent */
957 ext4_extent_set_block_count(path_ptr->extent, 1, false);
958 ext4_extent_set_first_block(path_ptr->extent, new_block_idx);
959 ext4_extent_set_start(path_ptr->extent, phys_block);
963 ext4_inode_set_size(inode_ref->inode, inode_size + block_size);
964 inode_ref->dirty = true;
967 path_ptr->block.dirty = true;
970 /* Set return values */
971 *iblock = new_block_idx;
972 *fblock = phys_block;
976 * starting from 1: 0 is a block with inode data
978 for (i = 1; i <= path->depth; ++i) {
979 if (path[i].block.lb_id) {
981 ext4_block_set(inode_ref->fs->bdev, &path[i].block);
987 /* Destroy temporary data structure */