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"
53 #if !CONFIG_EXTENT_FULL
55 /**@brief Binary search in extent index node.
56 * @param header Extent header of index node
57 * @param index Output value - found index will be set here
58 * @param iblock Logical block number to find in index node */
59 static void ext4_extent_binsearch_idx(struct ext4_extent_header *header,
60 struct ext4_extent_index **index,
63 struct ext4_extent_index *r;
64 struct ext4_extent_index *l;
65 struct ext4_extent_index *m;
67 uint16_t entries_count = ext4_extent_header_get_entries_count(header);
69 /* Initialize bounds */
70 l = EXT4_EXTENT_FIRST_INDEX(header) + 1;
71 r = EXT4_EXTENT_FIRST_INDEX(header) + entries_count - 1;
73 /* Do binary search */
76 uint32_t first_block = ext4_extent_index_get_first_block(m);
78 if (iblock < first_block)
84 /* Set output value */
88 /**@brief Binary search in extent leaf node.
89 * @param header Extent header of leaf node
90 * @param extent Output value - found extent will be set here,
91 * or NULL if node is empty
92 * @param iblock Logical block number to find in leaf node */
93 static void ext4_extent_binsearch(struct ext4_extent_header *header,
94 struct ext4_extent **extent, uint32_t iblock)
96 struct ext4_extent *r;
97 struct ext4_extent *l;
98 struct ext4_extent *m;
100 uint16_t entries_count = ext4_extent_header_get_entries_count(header);
102 if (entries_count == 0) {
103 /* this leaf is empty */
108 /* Initialize bounds */
109 l = EXT4_EXTENT_FIRST(header) + 1;
110 r = EXT4_EXTENT_FIRST(header) + entries_count - 1;
112 /* Do binary search */
115 uint32_t first_block = ext4_extent_get_first_block(m);
117 if (iblock < first_block)
123 /* Set output value */
127 static uint32_t ext4_ext_block_csum(struct ext4_inode_ref *inode_ref,
128 struct ext4_extent_header *eh)
130 uint32_t checksum = 0;
131 struct ext4_sblock *sb = &inode_ref->fs->sb;
133 if (ext4_sb_has_feature_read_only(sb,
134 EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) {
135 uint32_t ino_index = to_le32(inode_ref->index);
137 to_le32(ext4_inode_get_generation(inode_ref->inode));
138 /* First calculate crc32 checksum against fs uuid */
139 checksum = ext4_crc32c(~0, sb->uuid, sizeof(sb->uuid));
140 /* Then calculate crc32 checksum against inode number
141 * and inode generation */
142 checksum = ext4_crc32c(checksum, &ino_index,
144 checksum = ext4_crc32c(checksum, &ino_gen,
146 /* Finally calculate crc32 checksum against
147 * the entire extent block up to the checksum field */
148 checksum = ext4_crc32c(checksum, eh,
149 EXT4_EXTENT_TAIL_OFFSET(eh));
156 * Currently we do not verify the checksum of extent
157 * (only the case in ext4_extent.c)
160 static void ext4_extent_block_csum_set(struct ext4_inode_ref *inode_ref,
161 struct ext4_extent_header *eh)
163 struct ext4_extent_tail *tail;
165 tail = find_ext4_extent_tail(eh);
166 tail->et_checksum = to_le32(ext4_ext_block_csum(inode_ref, eh));
169 /**@brief Get physical block in the extent tree by logical block number.
170 * There is no need to save path in the tree during this algorithm.
171 * @param inode_ref I-node to load block from
172 * @param iblock Logical block number to find
173 * @param fblock Output value for physical block number
174 * @return Error code*/
176 ext4_extent_find_block(struct ext4_inode_ref *inode_ref, uint32_t iblock,
177 ext4_fsblk_t *fblock)
180 /* Compute bound defined by i-node size */
181 uint64_t inode_size =
182 ext4_inode_get_size(&inode_ref->fs->sb, inode_ref->inode);
184 uint32_t block_size = ext4_sb_get_block_size(&inode_ref->fs->sb);
186 uint32_t last_idx = (inode_size - 1) / block_size;
188 /* Check if requested iblock is not over size of i-node */
189 if (iblock > last_idx) {
194 struct ext4_block block;
197 /* Walk through extent tree */
198 struct ext4_extent_header *header =
199 ext4_inode_get_extent_header(inode_ref->inode);
201 while (ext4_extent_header_get_depth(header) != 0) {
202 /* Search index in node */
203 struct ext4_extent_index *index;
204 ext4_extent_binsearch_idx(header, &index, iblock);
206 /* Load child node and set values for the next iteration */
207 uint64_t child = ext4_extent_index_get_leaf(index);
210 rc = ext4_block_set(inode_ref->fs->bdev, &block);
215 int rc = ext4_block_get(inode_ref->fs->bdev, &block, child);
219 header = (struct ext4_extent_header *)block.data;
222 /* Search extent in the leaf block */
223 struct ext4_extent *extent = NULL;
224 ext4_extent_binsearch(header, &extent, iblock);
226 /* Prevent empty leaf */
227 if (extent == NULL) {
230 /* Compute requested physical block address */
231 ext4_fsblk_t phys_block;
232 uint32_t first = ext4_extent_get_first_block(extent);
233 phys_block = ext4_extent_get_start(extent) + iblock - first;
235 *fblock = phys_block;
240 rc = ext4_block_set(inode_ref->fs->bdev, &block);
248 /**@brief Find extent for specified iblock.
249 * This function is used for finding block in the extent tree with
250 * saving the path through the tree for possible future modifications.
251 * @param inode_ref I-node to read extent tree from
252 * @param iblock Iblock to find extent for
253 * @param ret_path Output value for loaded path from extent tree
254 * @return Error code */
255 static int ext4_extent_find_extent(struct ext4_inode_ref *inode_ref,
257 struct ext4_extent_path **ret_path)
259 struct ext4_extent_header *eh =
260 ext4_inode_get_extent_header(inode_ref->inode);
262 uint16_t depth = ext4_extent_header_get_depth(eh);
264 struct ext4_extent_path *tmp_path;
266 /* Added 2 for possible tree growing */
267 tmp_path = malloc(sizeof(struct ext4_extent_path) * (depth + 2));
268 if (tmp_path == NULL)
271 /* Initialize structure for algorithm start */
272 tmp_path[0].block = inode_ref->block;
273 tmp_path[0].header = eh;
275 /* Walk through the extent tree */
278 while (ext4_extent_header_get_depth(eh) != 0) {
279 /* Search index in index node by iblock */
280 ext4_extent_binsearch_idx(tmp_path[pos].header,
281 &tmp_path[pos].index, iblock);
283 tmp_path[pos].depth = depth;
284 tmp_path[pos].extent = NULL;
286 ext4_assert(tmp_path[pos].index != 0);
288 /* Load information for the next iteration */
290 ext4_extent_index_get_leaf(tmp_path[pos].index);
292 struct ext4_block block;
293 rc = ext4_block_get(inode_ref->fs->bdev, &block, fblock);
299 eh = (struct ext4_extent_header *)block.data;
300 tmp_path[pos].block = block;
301 tmp_path[pos].header = eh;
304 tmp_path[pos].depth = 0;
305 tmp_path[pos].extent = NULL;
306 tmp_path[pos].index = NULL;
308 /* Find extent in the leaf node */
309 ext4_extent_binsearch(tmp_path[pos].header, &tmp_path[pos].extent,
311 *ret_path = tmp_path;
318 * From 1: 0 is a block with inode data
320 for (i = 1; i < tmp_path->depth; ++i) {
321 if (tmp_path[i].block.lb_id) {
322 int r = ext4_block_set(inode_ref->fs->bdev,
329 /* Destroy temporary data structure */
335 /**@brief Release extent and all data blocks covered by the extent.
336 * @param inode_ref I-node to release extent and block from
337 * @param extent Extent to release
338 * @return Error code */
339 static int ext4_extent_release(struct ext4_inode_ref *inode_ref,
340 struct ext4_extent *extent)
342 /* Compute number of the first physical block to release */
343 uint64_t start = ext4_extent_get_start(extent);
344 uint16_t block_count = ext4_extent_get_block_count(extent);
346 return ext4_balloc_free_blocks(inode_ref, start, block_count);
349 /** Recursively release the whole branch of the extent tree.
350 * For each entry of the node release the subbranch and finally release
351 * the node. In the leaf node all extents will be released.
352 * @param inode_ref I-node where the branch is released
353 * @param index Index in the non-leaf node to be released
354 * with the whole subtree
355 * @return Error code */
356 static int ext4_extent_release_branch(struct ext4_inode_ref *inode_ref,
357 struct ext4_extent_index *index)
359 ext4_fsblk_t fblock = ext4_extent_index_get_leaf(index);
361 struct ext4_block block;
362 int rc = ext4_block_get(inode_ref->fs->bdev, &block, fblock);
366 struct ext4_extent_header *header = (void *)block.data;
368 if (ext4_extent_header_get_depth(header)) {
369 /* The node is non-leaf, do recursion */
370 struct ext4_extent_index *idx = EXT4_EXTENT_FIRST_INDEX(header);
372 /* Release all subbranches */
373 for (i = 0; i < ext4_extent_header_get_entries_count(header);
375 rc = ext4_extent_release_branch(inode_ref, idx);
380 /* Leaf node reached */
381 struct ext4_extent *ext = EXT4_EXTENT_FIRST(header);
383 /* Release all extents and stop recursion */
384 for (i = 0; i < ext4_extent_header_get_entries_count(header);
386 rc = ext4_extent_release(inode_ref, ext);
392 /* Release data block where the node was stored */
394 rc = ext4_block_set(inode_ref->fs->bdev, &block);
398 return ext4_balloc_free_block(inode_ref, fblock);
401 int ext4_extent_remove_space(struct ext4_inode_ref *inode_ref, ext4_lblk_t from,
404 if (to != EXT_MAX_BLOCKS)
407 /* Find the first extent to modify */
408 struct ext4_extent_path *path;
410 int rc = ext4_extent_find_extent(inode_ref, from, &path);
414 /* Jump to last item of the path (extent) */
415 struct ext4_extent_path *path_ptr = path;
416 while (path_ptr->depth != 0)
419 ext4_assert(path_ptr->extent != NULL);
421 /* First extent maybe released partially */
422 uint32_t first_iblock = ext4_extent_get_first_block(path_ptr->extent);
423 ext4_fsblk_t first_fblock = ext4_extent_get_start(path_ptr->extent) +
426 uint16_t block_count = ext4_extent_get_block_count(path_ptr->extent);
428 uint16_t delete_count =
430 (ext4_extent_get_start(path_ptr->extent) - first_fblock);
432 /* Release all blocks */
433 rc = ext4_balloc_free_blocks(inode_ref, first_fblock, delete_count);
437 /* Correct counter */
438 block_count -= delete_count;
439 ext4_extent_set_block_count(path_ptr->extent, block_count,
440 EXT4_EXT_IS_UNWRITTEN(path_ptr->extent));
442 /* Initialize the following loop */
444 ext4_extent_header_get_entries_count(path_ptr->header);
445 struct ext4_extent *tmp_ext = path_ptr->extent + 1;
446 struct ext4_extent *stop_ext =
447 EXT4_EXTENT_FIRST(path_ptr->header) + entries;
449 /* If first extent empty, release it */
450 if (block_count == 0)
453 /* Release all successors of the first extent in the same node */
454 while (tmp_ext < stop_ext) {
455 first_fblock = ext4_extent_get_start(tmp_ext);
456 delete_count = ext4_extent_get_block_count(tmp_ext);
458 rc = ext4_balloc_free_blocks(inode_ref, first_fblock,
467 ext4_extent_header_set_entries_count(path_ptr->header, entries);
468 ext4_extent_block_csum_set(inode_ref, path_ptr->header);
469 path_ptr->block.dirty = true;
471 /* If leaf node is empty, parent entry must be modified */
472 bool remove_parent_record = false;
474 /* Don't release root block (including inode data) !!! */
475 if ((path_ptr != path) && (entries == 0)) {
476 rc = ext4_balloc_free_block(inode_ref, path_ptr->block.lb_id);
480 remove_parent_record = true;
483 /* Jump to the parent */
486 /* Release all successors in all tree levels */
487 while (path_ptr >= path) {
489 ext4_extent_header_get_entries_count(path_ptr->header);
490 struct ext4_extent_index *index = path_ptr->index + 1;
491 struct ext4_extent_index *stop =
492 EXT4_EXTENT_FIRST_INDEX(path_ptr->header) + entries;
494 /* Correct entries count because of changes in the previous
496 if (remove_parent_record)
499 /* Iterate over all entries and release the whole subtrees */
500 while (index < stop) {
501 rc = ext4_extent_release_branch(inode_ref, index);
509 ext4_extent_header_set_entries_count(path_ptr->header, entries);
510 ext4_extent_block_csum_set(inode_ref, path_ptr->header);
511 path_ptr->block.dirty = true;
513 /* Free the node if it is empty */
514 if ((entries == 0) && (path_ptr != path)) {
515 rc = ext4_balloc_free_block(inode_ref,
516 path_ptr->block.lb_id);
520 /* Mark parent to be checked */
521 remove_parent_record = true;
523 remove_parent_record = false;
529 ext4_extent_header_set_depth(path->header, 0);
534 * starting from 1: 0 is a block with inode data
536 for (i = 1; i <= path->depth; ++i) {
537 if (path[i].block.lb_id) {
539 ext4_block_set(inode_ref->fs->bdev, &path[i].block);
545 /* Destroy temporary data structure */
551 /**@brief Append new extent to the i-node and do some splitting if necessary.
552 * @param inode_ref I-node to append extent to
553 * @param path Path in the extent tree for possible splitting
554 * @param last_path_item Input/output parameter for pointer to the last
555 * valid item in the extent tree path
556 * @param iblock Logical index of block to append extent for
557 * @return Error code */
558 static int ext4_extent_append_extent(struct ext4_inode_ref *inode_ref,
559 struct ext4_extent_path *path,
562 struct ext4_extent_path *path_ptr = path + path->depth;
564 uint32_t block_size = ext4_sb_get_block_size(&inode_ref->fs->sb);
566 /* Start splitting */
567 while (path_ptr > path) {
569 ext4_extent_header_get_entries_count(path_ptr->header);
571 ext4_extent_header_get_max_entries_count(path_ptr->header);
573 if (entries == limit) {
574 /* Full node - allocate block for new one */
575 ext4_fsblk_t goal, fblock;
576 int rc = ext4_fs_indirect_find_goal(inode_ref, &goal);
580 rc = ext4_balloc_alloc_block(inode_ref, goal, &fblock);
584 struct ext4_block block;
586 ext4_block_get(inode_ref->fs->bdev, &block, fblock);
588 ext4_balloc_free_block(inode_ref, fblock);
592 /* Put back not modified old block */
593 rc = ext4_block_set(inode_ref->fs->bdev,
596 ext4_balloc_free_block(inode_ref, fblock);
600 /* Initialize newly allocated block and remember it */
601 memset(block.data, 0, block_size);
602 path_ptr->block = block;
604 /* Update pointers in extent path structure */
605 path_ptr->header = (void *)block.data;
606 if (path_ptr->depth) {
608 EXT4_EXTENT_FIRST_INDEX(path_ptr->header);
609 ext4_extent_index_set_first_block(
610 path_ptr->index, iblock);
611 ext4_extent_index_set_leaf(
613 (path_ptr + 1)->block.lb_id);
614 limit = (block_size -
615 sizeof(struct ext4_extent_header)) /
616 sizeof(struct ext4_extent_index);
619 EXT4_EXTENT_FIRST(path_ptr->header);
620 ext4_extent_set_first_block(path_ptr->extent,
622 limit = (block_size -
623 sizeof(struct ext4_extent_header)) /
624 sizeof(struct ext4_extent);
627 /* Initialize on-disk structure (header) */
628 ext4_extent_header_set_entries_count(path_ptr->header,
630 ext4_extent_header_set_max_entries_count(
631 path_ptr->header, limit);
632 ext4_extent_header_set_magic(path_ptr->header,
634 ext4_extent_header_set_depth(path_ptr->header,
636 ext4_extent_header_set_generation(path_ptr->header, 0);
638 ext4_extent_block_csum_set(inode_ref, path_ptr->header);
639 path_ptr->block.dirty = true;
641 /* Jump to the preceding item */
644 /* Node with free space */
645 if (path_ptr->depth) {
647 EXT4_EXTENT_FIRST_INDEX(path_ptr->header) +
649 ext4_extent_index_set_first_block(
650 path_ptr->index, iblock);
651 ext4_extent_index_set_leaf(
653 (path_ptr + 1)->block.lb_id);
656 EXT4_EXTENT_FIRST(path_ptr->header) +
658 ext4_extent_set_first_block(path_ptr->extent,
662 ext4_extent_header_set_entries_count(path_ptr->header,
664 ext4_extent_block_csum_set(inode_ref, path_ptr->header);
665 path_ptr->block.dirty = true;
667 /* No more splitting needed */
672 ext4_assert(path_ptr == path);
674 /* Should be the root split too? */
676 uint16_t entries = ext4_extent_header_get_entries_count(path->header);
677 uint16_t limit = ext4_extent_header_get_max_entries_count(path->header);
679 if (entries == limit) {
680 ext4_fsblk_t goal, new_fblock;
681 int rc = ext4_fs_indirect_find_goal(inode_ref, &goal);
685 rc = ext4_balloc_alloc_block(inode_ref, goal, &new_fblock);
689 struct ext4_block block;
690 rc = ext4_block_get(inode_ref->fs->bdev, &block, new_fblock);
694 /* Initialize newly allocated block */
695 memset(block.data, 0, block_size);
697 /* Move data from root to the new block */
698 memcpy(block.data, inode_ref->inode->blocks,
699 EXT4_INODE_BLOCKS * sizeof(uint32_t));
701 /* Data block is initialized */
703 struct ext4_block *root_block = &path->block;
704 uint16_t root_depth = path->depth;
705 struct ext4_extent_header *root_header = path->header;
707 /* Make space for tree growing */
708 struct ext4_extent_path *new_root = path;
709 struct ext4_extent_path *old_root = path + 1;
712 sizeof(struct ext4_extent_path) * (path->depth + 1);
713 memmove(old_root, new_root, nbytes);
714 memset(new_root, 0, sizeof(struct ext4_extent_path));
716 /* Update old root structure */
717 old_root->block = block;
718 old_root->header = (struct ext4_extent_header *)block.data;
720 /* Add new entry and update limit for entries */
721 if (old_root->depth) {
723 (block_size - sizeof(struct ext4_extent_header)) /
724 sizeof(struct ext4_extent_index);
726 EXT4_EXTENT_FIRST_INDEX(old_root->header) + entries;
727 ext4_extent_index_set_first_block(old_root->index,
729 ext4_extent_index_set_leaf(old_root->index,
730 (old_root + 1)->block.lb_id);
731 old_root->extent = NULL;
734 (block_size - sizeof(struct ext4_extent_header)) /
735 sizeof(struct ext4_extent);
737 EXT4_EXTENT_FIRST(old_root->header) + entries;
738 ext4_extent_set_first_block(old_root->extent, iblock);
739 old_root->index = NULL;
742 ext4_extent_header_set_entries_count(old_root->header,
744 ext4_extent_header_set_max_entries_count(old_root->header,
747 ext4_extent_block_csum_set(inode_ref, ext_block_hdr(old_root->block));
748 old_root->block.dirty = true;
750 /* Re-initialize new root metadata */
751 new_root->depth = root_depth + 1;
752 new_root->block = *root_block;
753 new_root->header = root_header;
754 new_root->extent = NULL;
755 new_root->index = EXT4_EXTENT_FIRST_INDEX(new_root->header);
757 ext4_extent_header_set_depth(new_root->header, new_root->depth);
759 /* Create new entry in root */
760 ext4_extent_header_set_entries_count(new_root->header, 1);
761 ext4_extent_index_set_first_block(new_root->index, 0);
762 ext4_extent_index_set_leaf(new_root->index, new_fblock);
764 /* Since new_root belongs to on-disk inode,
765 * we don't do checksum here */
766 new_root->block.dirty = true;
770 EXT4_EXTENT_FIRST_INDEX(path->header) + entries;
771 ext4_extent_index_set_first_block(path->index, iblock);
772 ext4_extent_index_set_leaf(path->index,
773 (path + 1)->block.lb_id);
776 EXT4_EXTENT_FIRST(path->header) + entries;
777 ext4_extent_set_first_block(path->extent, iblock);
780 ext4_extent_header_set_entries_count(path->header, entries + 1);
781 /* Since new_root belongs to on-disk inode,
782 * we don't do checksum here */
783 path->block.dirty = true;
789 /**@brief Append data block to the i-node.
790 * This function allocates data block, tries to append it
791 * to some existing extent or creates new extents.
792 * It includes possible extent tree modifications (splitting).
793 * @param inode_ref I-node to append block to
794 * @param iblock Output logical number of newly allocated block
795 * @param fblock Output physical block address of newly allocated block
797 * @return Error code*/
799 ext4_extent_append_block(struct ext4_inode_ref *inode_ref, uint32_t *iblock,
800 ext4_fsblk_t *fblock, bool update_size)
804 struct ext4_sblock *sb = &inode_ref->fs->sb;
805 uint64_t inode_size = ext4_inode_get_size(sb, inode_ref->inode);
806 uint32_t block_size = ext4_sb_get_block_size(sb);
808 /* Calculate number of new logical block */
809 uint32_t new_block_idx = 0;
810 if (inode_size > 0) {
811 if ((inode_size % block_size) != 0)
812 inode_size += block_size - (inode_size % block_size);
814 new_block_idx = inode_size / block_size;
817 /* Load the nearest leaf (with extent) */
818 struct ext4_extent_path *path;
819 int rc = ext4_extent_find_extent(inode_ref, new_block_idx, &path);
823 /* Jump to last item of the path (extent) */
824 struct ext4_extent_path *path_ptr = path;
825 while (path_ptr->depth != 0)
828 /* Add new extent to the node if not present */
829 if (path_ptr->extent == NULL)
832 uint16_t block_count = ext4_extent_get_block_count(path_ptr->extent);
833 uint16_t block_limit = (1 << 15);
835 ext4_fsblk_t phys_block = 0;
836 if (block_count < block_limit) {
837 /* There is space for new block in the extent */
838 if (block_count == 0) {
839 int rc = ext4_fs_indirect_find_goal(inode_ref, &goal);
843 /* Existing extent is empty */
844 rc = ext4_balloc_alloc_block(inode_ref, goal, &phys_block);
848 /* Initialize extent */
849 ext4_extent_set_first_block(path_ptr->extent,
851 ext4_extent_set_start(path_ptr->extent, phys_block);
852 ext4_extent_set_block_count(path_ptr->extent, 1,
857 ext4_inode_set_size(inode_ref->inode,
858 inode_size + block_size);
859 inode_ref->dirty = true;
862 ext4_extent_block_csum_set(inode_ref, ext_block_hdr(path_ptr->block));
863 path_ptr->block.dirty = true;
868 int rc = ext4_fs_indirect_find_goal(inode_ref, &goal);
872 /* Existing extent contains some blocks */
873 phys_block = ext4_extent_get_start(path_ptr->extent);
875 ext4_extent_get_block_count(path_ptr->extent);
877 /* Check if the following block is free for allocation
880 rc = ext4_balloc_try_alloc_block(inode_ref, phys_block,
886 /* Target is not free, new block must be
887 * appended to new extent
893 ext4_extent_set_block_count(path_ptr->extent,
899 ext4_inode_set_size(inode_ref->inode,
900 inode_size + block_size);
901 inode_ref->dirty = true;
904 ext4_extent_block_csum_set(inode_ref, ext_block_hdr(path_ptr->block));
905 path_ptr->block.dirty = true;
912 /* Append new extent to the tree */
915 rc = ext4_fs_indirect_find_goal(inode_ref, &goal);
919 /* Allocate new data block */
920 rc = ext4_balloc_alloc_block(inode_ref, goal, &phys_block);
924 /* Append extent for new block (includes tree splitting if needed) */
925 rc = ext4_extent_append_extent(inode_ref, path, new_block_idx);
927 ext4_balloc_free_block(inode_ref, phys_block);
931 uint32_t tree_depth = ext4_extent_header_get_depth(path->header);
932 path_ptr = path + tree_depth;
934 /* Initialize newly created extent */
935 ext4_extent_set_block_count(path_ptr->extent, 1, false);
936 ext4_extent_set_first_block(path_ptr->extent, new_block_idx);
937 ext4_extent_set_start(path_ptr->extent, phys_block);
941 ext4_inode_set_size(inode_ref->inode, inode_size + block_size);
942 inode_ref->dirty = true;
945 ext4_extent_block_csum_set(inode_ref, ext_block_hdr(path_ptr->block));
946 path_ptr->block.dirty = true;
949 /* Set return values */
950 *iblock = new_block_idx;
951 *fblock = phys_block;
955 * starting from 1: 0 is a block with inode data
957 for (i = 1; i <= path->depth; ++i) {
958 if (path[i].block.lb_id) {
960 ext4_block_set(inode_ref->fs->bdev, &path[i].block);
966 /* Destroy temporary data structure */
972 int ext4_extent_get_blocks(struct ext4_inode_ref *inode_ref, ext4_fsblk_t iblock,
973 ext4_lblk_t max_blocks, ext4_fsblk_t *result, bool create,
974 ext4_lblk_t *blocks_count)
976 uint32_t iblk = iblock;
977 ext4_fsblk_t fblk = 0;
986 r = ext4_extent_find_block(inode_ref, iblk, &fblk);
988 r = ext4_extent_append_block(inode_ref, &iblk, &fblk, false);