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.
33 /** @addtogroup lwext4
38 * @brief More complex filesystem functions.
41 #include <ext4_config.h>
42 #include <ext4_types.h>
44 #include <ext4_errno.h>
45 #include <ext4_blockdev.h>
46 #include <ext4_super.h>
47 #include <ext4_debug.h>
48 #include <ext4_block_group.h>
49 #include <ext4_balloc.h>
50 #include <ext4_bitmap.h>
51 #include <ext4_inode.h>
52 #include <ext4_ialloc.h>
55 int ext4_fs_init(struct ext4_fs *fs, struct ext4_blockdev *bdev)
60 bool read_only = false;
62 ext4_assert(fs && bdev);
66 r = ext4_sb_read(fs->bdev, &fs->sb);
70 if(!ext4_sb_check(&fs->sb))
73 bsize = ext4_sb_get_block_size(&fs->sb);
74 if (bsize > EXT4_MAX_BLOCK_SIZE)
77 r = ext4_fs_check_features(fs, &read_only);
84 /* Compute limits for indirect block levels */
85 uint32_t blocks_id = bsize / sizeof(uint32_t);
87 fs->inode_block_limits[0] = EXT4_INODE_DIRECT_BLOCK_COUNT;
88 fs->inode_blocks_per_level[0] = 1;
90 for (i = 1; i < 4; i++) {
91 fs->inode_blocks_per_level[i] = fs->inode_blocks_per_level[i - 1] *
93 fs->inode_block_limits[i] = fs->inode_block_limits[i - 1] +
94 fs->inode_blocks_per_level[i];
98 tmp = ext4_get16(&fs->sb, state);
99 if (tmp & EXT4_SUPERBLOCK_STATE_ERROR_FS) {
100 ext4_dprintf(EXT4_DEBUG_FS,
101 "Filesystem was not cleanly unmounted before \n");
104 /* Mark system as mounted */
105 ext4_set16(&fs->sb, state, EXT4_SUPERBLOCK_STATE_ERROR_FS);
106 r = ext4_sb_write(fs->bdev, &fs->sb);
111 /*Update mount count*/
112 ext4_set16(&fs->sb, mount_count, ext4_get16(&fs->sb, mount_count) + 1);
118 int ext4_fs_fini(struct ext4_fs *fs)
122 /*Set superblock state*/
123 ext4_set16(&fs->sb, state, EXT4_SUPERBLOCK_STATE_VALID_FS);
125 return ext4_sb_write(fs->bdev, &fs->sb);
128 int ext4_fs_check_features(struct ext4_fs *fs, bool *read_only)
130 ext4_assert(fs && read_only);
132 if(ext4_get32(&fs->sb, rev_level) == 0){
137 /*Check features_incompatible*/
138 if ((ext4_get32(&fs->sb, features_incompatible) &
139 (~EXT4_FEATURE_INCOMPAT_SUPP)) )
143 /*Check features_read_only*/
144 if ((ext4_get32(&fs->sb, features_read_only) &
145 (~EXT4_FEATURE_RO_COMPAT_SUPP))){
155 uint32_t ext4_fs_baddr2_index_in_group(struct ext4_sblock *s, uint32_t baddr)
158 if(ext4_get32(s, first_data_block))
161 return baddr % ext4_get32(s, blocks_per_group);
166 uint32_t ext4_fs_index_in_group2_baddr(struct ext4_sblock *s, uint32_t index,
169 if(ext4_get32(s, first_data_block))
172 return ext4_get32(s, blocks_per_group) * bgid + index;
178 static int ext4_fs_init_block_bitmap(struct ext4_block_group_ref *bg_ref)
181 uint32_t bitmap_block_addr = ext4_bg_get_block_bitmap(
182 bg_ref->block_group, &bg_ref->fs->sb);
184 struct ext4_block block_bitmap;
185 int rc = ext4_block_get(bg_ref->fs->bdev, &block_bitmap,
191 memset(block_bitmap.data, 0, ext4_sb_get_block_size(&bg_ref->fs->sb));
193 /* Determine first block and first data block in group */
194 uint32_t first_idx = 0;
196 uint32_t first_data = ext4_balloc_get_first_data_block_in_group(
197 &bg_ref->fs->sb, bg_ref);
198 uint32_t first_data_idx = ext4_fs_baddr2_index_in_group(
199 &bg_ref->fs->sb, first_data);
201 /*Set bits from to first block to first data block - 1 to one (allocated)*/
202 /*TODO: Optimize it*/
203 for (i = first_idx; i < first_data_idx; ++i)
204 ext4_bmap_bit_set(block_bitmap.data, i);
207 block_bitmap.dirty = true;
210 return ext4_block_set(bg_ref->fs->bdev, &block_bitmap);
213 static int ext4_fs_init_inode_bitmap(struct ext4_block_group_ref *bg_ref)
216 uint32_t bitmap_block_addr = ext4_bg_get_inode_bitmap(
217 bg_ref->block_group, &bg_ref->fs->sb);
219 struct ext4_block block_bitmap;
220 int rc = ext4_block_get(bg_ref->fs->bdev, &block_bitmap,
225 /* Initialize all bitmap bits to zero */
226 uint32_t block_size = ext4_sb_get_block_size(&bg_ref->fs->sb);
227 uint32_t inodes_per_group = ext4_get32(&bg_ref->fs->sb, inodes_per_group);
229 memset(block_bitmap.data, 0, (inodes_per_group + 7) / 8);
231 uint32_t start_bit = inodes_per_group;
232 uint32_t end_bit = block_size * 8;
235 for (i = start_bit; i < ((start_bit + 7) & ~7UL); i++)
236 ext4_bmap_bit_set(block_bitmap.data, i);
239 memset(block_bitmap.data + (i >> 3), 0xff, (end_bit - i) >> 3);
241 block_bitmap.dirty = true;
244 return ext4_block_set(bg_ref->fs->bdev, &block_bitmap);
247 static int ext4_fs_init_inode_table(struct ext4_block_group_ref *bg_ref)
249 struct ext4_sblock *sb = &bg_ref->fs->sb;
251 uint32_t inode_size = ext4_get32(sb, inode_size);
252 uint32_t block_size = ext4_sb_get_block_size(sb);
253 uint32_t inodes_per_block = block_size / inode_size;
254 uint32_t inodes_in_group = ext4_inodes_in_group_cnt(sb, bg_ref->index);
255 uint32_t table_blocks = inodes_in_group / inodes_per_block;
258 if (inodes_in_group % inodes_per_block)
261 /* Compute initialization bounds */
262 uint32_t first_block = ext4_bg_get_inode_table_first_block(
263 bg_ref->block_group, sb);
265 uint32_t last_block = first_block + table_blocks - 1;
267 /* Initialization of all itable blocks */
268 for (fblock = first_block; fblock <= last_block; ++fblock) {
270 struct ext4_block block;
271 int rc = ext4_block_get(bg_ref->fs->bdev, &block, fblock);
275 memset(block.data, 0, block_size);
278 ext4_block_set(bg_ref->fs->bdev, &block);
287 int ext4_fs_get_block_group_ref(struct ext4_fs *fs, uint32_t bgid,
288 struct ext4_block_group_ref *ref)
290 /* Compute number of descriptors, that fits in one data block */
291 uint32_t dsc_per_block = ext4_sb_get_block_size(&fs->sb) /
292 ext4_sb_get_desc_size(&fs->sb);
294 /* Block group descriptor table starts at the next block after superblock */
295 uint64_t block_id = ext4_get32(&fs->sb, first_data_block) + 1;
297 /* Find the block containing the descriptor we are looking for */
298 block_id += bgid / dsc_per_block;
299 uint32_t offset = (bgid % dsc_per_block) *
300 ext4_sb_get_desc_size(&fs->sb);
303 int rc = ext4_block_get(fs->bdev, &ref->block, block_id);
307 ref->block_group = (void *)(ref->block.data + offset);
312 if (ext4_bg_has_flag(ref->block_group,
313 EXT4_BLOCK_GROUP_BLOCK_UNINIT)) {
314 rc = ext4_fs_init_block_bitmap(ref);
316 ext4_block_set(fs->bdev, &ref->block);
319 ext4_bg_clear_flag(ref->block_group,
320 EXT4_BLOCK_GROUP_BLOCK_UNINIT);
325 if (ext4_bg_has_flag(ref->block_group,
326 EXT4_BLOCK_GROUP_INODE_UNINIT)) {
327 rc = ext4_fs_init_inode_bitmap(ref);
329 ext4_block_set(ref->fs->bdev, &ref->block);
333 ext4_bg_clear_flag(ref->block_group,
334 EXT4_BLOCK_GROUP_INODE_UNINIT);
336 if (!ext4_bg_has_flag(ref->block_group,
337 EXT4_BLOCK_GROUP_ITABLE_ZEROED)) {
338 rc = ext4_fs_init_inode_table(ref);
340 ext4_block_set(fs->bdev, &ref->block);
344 ext4_bg_set_flag(ref->block_group,
345 EXT4_BLOCK_GROUP_ITABLE_ZEROED);
354 static uint16_t ext4_fs_bg_checksum(struct ext4_sblock *sb, uint32_t bgid,
355 struct ext4_bgroup *bg)
357 /* If checksum not supported, 0 will be returned */
360 /* Compute the checksum only if the filesystem supports it */
361 if (ext4_sb_check_read_only(sb,
362 EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) {
364 void *checksum = &bg->checksum;
366 uint32_t offset = (uint32_t) (checksum - base);
368 /* Convert block group index to little endian */
369 uint32_t le_group = to_le32(bgid);
372 crc = ext4_bg_crc16(~0, sb->uuid, sizeof(sb->uuid));
374 /* Include index of block group */
375 crc = ext4_bg_crc16(crc, (uint8_t *) &le_group, sizeof(le_group));
377 /* Compute crc from the first part (stop before checksum field) */
378 crc = ext4_bg_crc16(crc, (uint8_t *) bg, offset);
381 offset += sizeof(bg->checksum);
383 /* Checksum of the rest of block group descriptor */
384 if ((ext4_sb_check_feature_incompatible(sb,
385 EXT4_FEATURE_INCOMPAT_64BIT)) &&
386 (offset < ext4_sb_get_desc_size(sb)))
388 crc = ext4_bg_crc16(crc, ((uint8_t *) bg) + offset,
389 ext4_sb_get_desc_size(sb) - offset);
394 int ext4_fs_put_block_group_ref(struct ext4_block_group_ref *ref)
396 /* Check if reference modified */
398 /* Compute new checksum of block group */
400 ext4_fs_bg_checksum(&ref->fs->sb, ref->index,
403 ref->block_group->checksum = to_le16(checksum);
405 /* Mark block dirty for writing changes to physical device */
406 ref->block.dirty = true;
409 /* Put back block, that contains block group descriptor */
410 return ext4_block_set(ref->fs->bdev, &ref->block);
413 int ext4_fs_get_inode_ref(struct ext4_fs *fs, uint32_t index,
414 struct ext4_inode_ref *ref)
416 /* Compute number of i-nodes, that fits in one data block */
417 uint32_t inodes_per_group = ext4_get32(&fs->sb, inodes_per_group);
420 * Inode numbers are 1-based, but it is simpler to work with 0-based
421 * when computing indices
424 uint32_t block_group = index / inodes_per_group;
425 uint32_t offset_in_group = index % inodes_per_group;
427 /* Load block group, where i-node is located */
428 struct ext4_block_group_ref bg_ref;
430 int rc = ext4_fs_get_block_group_ref(fs, block_group, &bg_ref);
435 /* Load block address, where i-node table is located */
436 uint32_t inode_table_start =
437 ext4_bg_get_inode_table_first_block(bg_ref.block_group,
440 /* Put back block group reference (not needed more) */
441 rc = ext4_fs_put_block_group_ref(&bg_ref);
446 /* Compute position of i-node in the block group */
447 uint16_t inode_size = ext4_get16(&fs->sb, inode_size);
448 uint32_t block_size = ext4_sb_get_block_size(&fs->sb);
449 uint32_t byte_offset_in_group = offset_in_group * inode_size;
451 /* Compute block address */
452 uint64_t block_id = inode_table_start +
453 (byte_offset_in_group / block_size);
456 rc = ext4_block_get(fs->bdev, &ref->block, block_id);
461 /* Compute position of i-node in the data block */
462 uint32_t offset_in_block = byte_offset_in_group % block_size;
463 ref->inode = (struct ext4_inode *)(ref->block.data + offset_in_block);
465 /* We need to store the original value of index in the reference */
466 ref->index = index + 1;
473 int ext4_fs_put_inode_ref(struct ext4_inode_ref *ref)
475 /* Check if reference modified */
477 /* Mark block dirty for writing changes to physical device */
478 ref->block.dirty = true;
481 /* Put back block, that contains i-node */
482 return ext4_block_set(ref->fs->bdev, &ref->block);
485 int ext4_fs_alloc_inode(struct ext4_fs *fs, struct ext4_inode_ref *inode_ref,
488 /* Check if newly allocated i-node will be a directory */
492 is_dir = is_directory;
494 /* Allocate inode by allocation algorithm */
496 int rc = ext4_ialloc_alloc_inode(fs, &index, is_dir);
500 /* Load i-node from on-disk i-node table */
501 rc = ext4_fs_get_inode_ref(fs, index, inode_ref);
503 ext4_ialloc_free_inode(fs, index, is_dir);
507 /* Initialize i-node */
508 struct ext4_inode *inode = inode_ref->inode;
513 * Default directory permissions to be compatible with other systems
514 * 0777 (octal) == rwxrwxrwx
518 mode |= EXT4_INODE_MODE_DIRECTORY;
519 ext4_inode_set_mode(&fs->sb, inode, mode);
520 ext4_inode_set_links_count(inode, 1); /* '.' entry */
524 * Default file permissions to be compatible with other systems
525 * 0666 (octal) == rw-rw-rw-
529 mode |= EXT4_INODE_MODE_FILE;
530 ext4_inode_set_mode(&fs->sb, inode, mode);
531 ext4_inode_set_links_count(inode, 0);
534 ext4_inode_set_uid(inode, 0);
535 ext4_inode_set_gid(inode, 0);
536 ext4_inode_set_size(inode, 0);
537 ext4_inode_set_access_time(inode, 0);
538 ext4_inode_set_change_inode_time(inode, 0);
539 ext4_inode_set_modification_time(inode, 0);
540 ext4_inode_set_deletion_time(inode, 0);
541 ext4_inode_set_blocks_count(&fs->sb, inode, 0);
542 ext4_inode_set_flags(inode, 0);
543 ext4_inode_set_generation(inode, 0);
545 /* Reset blocks array */
546 for (i = 0; i < EXT4_INODE_BLOCKS; i++)
547 inode->blocks[i] = 0;
549 #if CONFIG_EXTENT_ENABLE
550 /* Initialize extents if needed */
551 if (ext4_sb_check_feature_incompatible(
552 &fs->sb, EXT4_FEATURE_INCOMPAT_EXTENTS)) {
553 ext4_inode_set_flag(inode, EXT4_INODE_FLAG_EXTENTS);
556 /* Initialize extent root header */
557 ext4_extent_header_t *header = ext4_inode_get_extent_header(inode);
558 ext4_extent_header_set_depth(header, 0);
559 ext4_extent_header_set_entries_count(header, 0);
560 ext4_extent_header_set_generation(header, 0);
561 ext4_extent_header_set_magic(header, EXT4_EXTENT_MAGIC);
563 uint16_t max_entries = (EXT4_INODE_BLOCKS * sizeof(uint32_t) -
564 sizeof(ext4_extent_header_t)) / sizeof(ext4_extent_t);
566 ext4_extent_header_set_max_entries_count(header, max_entries);
570 inode_ref->dirty = true;
575 int ext4_fs_free_inode(struct ext4_inode_ref *inode_ref)
577 struct ext4_fs *fs = inode_ref->fs;
580 #if CONFIG_EXTENT_ENABLE
581 /* For extents must be data block destroyed by other way */
582 if ((ext4_sb_check_feature_incompatible(&fs->sb,
583 EXT4_FEATURE_INCOMPAT_EXTENTS)) &&
584 (ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS))){
585 /* Data structures are released during truncate operation... */
589 /* Release all indirect (no data) blocks */
591 /* 1) Single indirect */
592 uint32_t fblock = ext4_inode_get_indirect_block(inode_ref->inode, 0);
594 int rc = ext4_balloc_free_block(inode_ref, fblock);
598 ext4_inode_set_indirect_block(inode_ref->inode, 0, 0);
601 uint32_t block_size = ext4_sb_get_block_size(&fs->sb);
602 uint32_t count = block_size / sizeof(uint32_t);
604 struct ext4_block block;
606 /* 2) Double indirect */
607 fblock = ext4_inode_get_indirect_block(inode_ref->inode, 1);
609 int rc = ext4_block_get(fs->bdev, &block, fblock);
614 for (offset = 0; offset < count; ++offset) {
615 ind_block = to_le32(((uint32_t *) block.data)[offset]);
617 if (ind_block != 0) {
618 rc = ext4_balloc_free_block(inode_ref, ind_block);
620 ext4_block_set(fs->bdev, &block);
626 ext4_block_set(fs->bdev, &block);
627 rc = ext4_balloc_free_block(inode_ref, fblock);
631 ext4_inode_set_indirect_block(inode_ref->inode, 1, 0);
634 /* 3) Tripple indirect */
635 struct ext4_block subblock;
636 fblock = ext4_inode_get_indirect_block(inode_ref->inode, 2);
638 int rc = ext4_block_get(fs->bdev, &block, fblock);
643 for ( offset = 0; offset < count; ++offset) {
644 ind_block = to_le32(((uint32_t *) block.data)[offset]);
646 if (ind_block != 0) {
647 rc = ext4_block_get(fs->bdev, &subblock, ind_block);
649 ext4_block_set(fs->bdev, &block);
653 uint32_t ind_subblock;
654 for (suboffset = 0; suboffset < count;
656 ind_subblock = to_le32(((uint32_t *)
657 subblock.data)[suboffset]);
659 if (ind_subblock != 0) {
660 rc = ext4_balloc_free_block(inode_ref, ind_subblock);
662 ext4_block_set(fs->bdev, &subblock);
663 ext4_block_set(fs->bdev, &block);
669 ext4_block_set(fs->bdev, &subblock);
672 rc = ext4_balloc_free_block(inode_ref, ind_block);
674 ext4_block_set(fs->bdev, &block);
680 ext4_block_set(fs->bdev, &block);
681 rc = ext4_balloc_free_block(inode_ref, fblock);
685 ext4_inode_set_indirect_block(inode_ref->inode, 2, 0);
689 /* Mark inode dirty for writing to the physical device */
690 inode_ref->dirty = true;
692 /* Free block with extended attributes if present */
693 uint32_t xattr_block = ext4_inode_get_file_acl(
694 inode_ref->inode, &fs->sb);
696 int rc = ext4_balloc_free_block(inode_ref, xattr_block);
700 ext4_inode_set_file_acl(inode_ref->inode, &fs->sb, 0);
703 /* Free inode by allocator */
705 if (ext4_inode_is_type(&fs->sb, inode_ref->inode,
706 EXT4_INODE_MODE_DIRECTORY))
707 rc = ext4_ialloc_free_inode(fs, inode_ref->index, true);
709 rc = ext4_ialloc_free_inode(fs, inode_ref->index, false);
714 int ext4_fs_truncate_inode(struct ext4_inode_ref *inode_ref,
717 struct ext4_sblock *sb = &inode_ref->fs->sb;
720 /* Check flags, if i-node can be truncated */
721 if (!ext4_inode_can_truncate(sb, inode_ref->inode))
724 /* If sizes are equal, nothing has to be done. */
725 uint64_t old_size = ext4_inode_get_size(sb, inode_ref->inode);
726 if (old_size == new_size)
729 /* It's not suppported to make the larger file by truncate operation */
730 if (old_size < new_size)
733 /* Compute how many blocks will be released */
734 uint64_t size_diff = old_size - new_size;
735 uint32_t block_size = ext4_sb_get_block_size(sb);
736 uint32_t diff_blocks_count = size_diff / block_size;
737 if (size_diff % block_size != 0)
740 uint32_t old_blocks_count = old_size / block_size;
741 if (old_size % block_size != 0)
743 #if CONFIG_EXTENT_ENABLE
744 if ((ext4_sb_check_feature_incompatible(sb,
745 EXT4_FEATURE_INCOMPAT_EXTENTS)) &&
746 (ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS))) {
748 /* Extents require special operation */
749 int rc = ext4_extent_release_blocks_from(inode_ref,
750 old_blocks_count - diff_blocks_count);
757 /* Release data blocks from the end of file */
759 /* Starting from 1 because of logical blocks are numbered from 0 */
760 for (i = 1; i <= diff_blocks_count; ++i) {
761 int rc = ext4_fs_release_inode_block(inode_ref,
762 old_blocks_count - i);
769 ext4_inode_set_size(inode_ref->inode, new_size);
770 inode_ref->dirty = true;
775 int ext4_fs_get_inode_data_block_index(struct ext4_inode_ref *inode_ref,
776 uint64_t iblock, uint32_t *fblock)
778 struct ext4_fs *fs = inode_ref->fs;
780 /* For empty file is situation simple */
781 if (ext4_inode_get_size(&fs->sb, inode_ref->inode) == 0) {
786 uint32_t current_block;
787 #if CONFIG_EXTENT_ENABLE
788 /* Handle i-node using extents */
789 if ((ext4_sb_check_feature_incompatible(&fs->sb,
790 EXT4_FEATURE_INCOMPAT_EXTENTS)) &&
791 (ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS))) {
794 int rc = ext4_extent_find_block(inode_ref, iblock, ¤t_block);
798 *fblock = current_block;
803 struct ext4_inode *inode = inode_ref->inode;
805 /* Direct block are read directly from array in i-node structure */
806 if (iblock < EXT4_INODE_DIRECT_BLOCK_COUNT) {
807 current_block = ext4_inode_get_direct_block(inode, (uint32_t) iblock);
808 *fblock = current_block;
812 /* Determine indirection level of the target block */
813 unsigned int level = 0;
815 for (i = 1; i < 4; i++) {
816 if (iblock < fs->inode_block_limits[i]) {
825 /* Compute offsets for the topmost level */
826 uint64_t block_offset_in_level =
827 iblock - fs->inode_block_limits[level - 1];
828 current_block = ext4_inode_get_indirect_block(inode, level - 1);
829 uint32_t offset_in_block =
830 block_offset_in_level / fs->inode_blocks_per_level[level - 1];
833 if (current_block == 0) {
838 struct ext4_block block;
841 * Navigate through other levels, until we find the block number
842 * or find null reference meaning we are dealing with sparse file
845 /* Load indirect block */
846 int rc = ext4_block_get(fs->bdev, &block, current_block);
850 /* Read block address from indirect block */
852 to_le32(((uint32_t *) block.data)[offset_in_block]);
854 /* Put back indirect block untouched */
855 rc = ext4_block_set(fs->bdev, &block);
859 /* Check for sparse file */
860 if (current_block == 0) {
865 /* Jump to the next level */
868 /* Termination condition - we have address of data block loaded */
872 /* Visit the next level */
873 block_offset_in_level %= fs->inode_blocks_per_level[level];
875 block_offset_in_level / fs->inode_blocks_per_level[level - 1];
878 *fblock = current_block;
883 int ext4_fs_set_inode_data_block_index(struct ext4_inode_ref *inode_ref,
884 uint64_t iblock, uint32_t fblock)
886 struct ext4_fs *fs = inode_ref->fs;
888 #if CONFIG_EXTENT_ENABLE
889 /* Handle inode using extents */
890 if ((ext4_sb_check_feature_incompatible(&fs->sb,
891 EXT4_FEATURE_INCOMPAT_EXTENTS)) &&
892 (ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS))) {
898 /* Handle simple case when we are dealing with direct reference */
899 if (iblock < EXT4_INODE_DIRECT_BLOCK_COUNT) {
900 ext4_inode_set_direct_block(inode_ref->inode, (uint32_t) iblock,
902 inode_ref->dirty = true;
907 /* Determine the indirection level needed to get the desired block */
908 unsigned int level = 0;
910 for (i = 1; i < 4; i++) {
911 if (iblock < fs->inode_block_limits[i]) {
920 uint32_t block_size = ext4_sb_get_block_size(&fs->sb);
922 /* Compute offsets for the topmost level */
923 uint64_t block_offset_in_level =
924 iblock - fs->inode_block_limits[level - 1];
925 uint32_t current_block =
926 ext4_inode_get_indirect_block(inode_ref->inode, level - 1);
927 uint32_t offset_in_block =
928 block_offset_in_level / fs->inode_blocks_per_level[level - 1];
930 uint32_t new_block_addr;
932 struct ext4_block block;
933 struct ext4_block new_block;
935 /* Is needed to allocate indirect block on the i-node level */
936 if (current_block == 0) {
937 /* Allocate new indirect block */
938 int rc = ext4_balloc_alloc_block(inode_ref, &new_block_addr);
943 ext4_inode_set_indirect_block(inode_ref->inode, level - 1,
945 inode_ref->dirty = true;
947 /* Load newly allocated block */
948 rc = ext4_block_get(fs->bdev, &new_block, new_block_addr);
950 ext4_balloc_free_block(inode_ref, new_block_addr);
954 /* Initialize new block */
955 memset(new_block.data, 0, block_size);
956 new_block.dirty = true;
958 /* Put back the allocated block */
959 rc = ext4_block_set(fs->bdev, &new_block);
963 current_block = new_block_addr;
967 * Navigate through other levels, until we find the block number
968 * or find null reference meaning we are dealing with sparse file
971 int rc = ext4_block_get(fs->bdev, &block, current_block);
976 to_le32(((uint32_t *) block.data)[offset_in_block]);
978 if ((level > 1) && (current_block == 0)) {
979 /* Allocate new block */
980 rc = ext4_balloc_alloc_block(inode_ref, &new_block_addr);
982 ext4_block_set(fs->bdev, &block);
986 /* Load newly allocated block */
987 rc = ext4_block_get(fs->bdev, &new_block, new_block_addr);
990 ext4_block_set(fs->bdev, &block);
994 /* Initialize allocated block */
995 memset(new_block.data, 0, block_size);
996 new_block.dirty = true;
998 rc = ext4_block_set(fs->bdev, &new_block);
1000 ext4_block_set(fs->bdev, &block);
1004 /* Write block address to the parent */
1005 ((uint32_t *) block.data)[offset_in_block] =
1006 to_le32(new_block_addr);
1008 current_block = new_block_addr;
1011 /* Will be finished, write the fblock address */
1013 ((uint32_t *) block.data)[offset_in_block] =
1018 rc = ext4_block_set(fs->bdev, &block);
1025 * If we are on the last level, break here as
1026 * there is no next level to visit
1031 /* Visit the next level */
1032 block_offset_in_level %= fs->inode_blocks_per_level[level];
1034 block_offset_in_level / fs->inode_blocks_per_level[level - 1];
1040 int ext4_fs_release_inode_block(struct ext4_inode_ref *inode_ref,
1045 struct ext4_fs *fs = inode_ref->fs;
1047 /* Extents are handled otherwise = there is not support in this function */
1048 ext4_assert(!(ext4_sb_check_feature_incompatible(&fs->sb,
1049 EXT4_FEATURE_INCOMPAT_EXTENTS) &&
1050 (ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS))));
1052 struct ext4_inode *inode = inode_ref->inode;
1054 /* Handle simple case when we are dealing with direct reference */
1055 if (iblock < EXT4_INODE_DIRECT_BLOCK_COUNT) {
1056 fblock = ext4_inode_get_direct_block(inode, iblock);
1062 ext4_inode_set_direct_block(inode, iblock, 0);
1063 return ext4_balloc_free_block(inode_ref, fblock);
1066 /* Determine the indirection level needed to get the desired block */
1067 unsigned int level = 0;
1069 for (i = 1; i < 4; i++) {
1070 if (iblock < fs->inode_block_limits[i]) {
1079 /* Compute offsets for the topmost level */
1080 uint64_t block_offset_in_level =
1081 iblock - fs->inode_block_limits[level - 1];
1082 uint32_t current_block =
1083 ext4_inode_get_indirect_block(inode, level - 1);
1084 uint32_t offset_in_block =
1085 block_offset_in_level / fs->inode_blocks_per_level[level - 1];
1088 * Navigate through other levels, until we find the block number
1089 * or find null reference meaning we are dealing with sparse file
1091 struct ext4_block block;
1096 if (current_block == 0)
1099 int rc = ext4_block_get(fs->bdev, &block, current_block);
1104 to_le32(((uint32_t *) block.data)[offset_in_block]);
1106 /* Set zero if physical data block address found */
1108 ((uint32_t *) block.data)[offset_in_block] =
1113 rc = ext4_block_set(fs->bdev, &block);
1120 * If we are on the last level, break here as
1121 * there is no next level to visit
1126 /* Visit the next level */
1127 block_offset_in_level %= fs->inode_blocks_per_level[level];
1129 block_offset_in_level / fs->inode_blocks_per_level[level - 1];
1132 fblock = current_block;
1136 /* Physical block is not referenced, it can be released */
1137 return ext4_balloc_free_block(inode_ref, fblock);
1141 int ext4_fs_append_inode_block(struct ext4_inode_ref *inode_ref,
1142 uint32_t *fblock, uint32_t *iblock)
1144 #if CONFIG_EXTENT_ENABLE
1145 /* Handle extents separately */
1146 if ((ext4_sb_check_feature_incompatible(&inode_ref->fs->sb,
1147 EXT4_FEATURE_INCOMPAT_EXTENTS)) &&
1148 (ext4_inode_has_flag(inode_ref->inode, EXT4_INODE_FLAG_EXTENTS))){
1149 return ext4_extent_append_block(inode_ref, iblock, fblock, true);
1152 struct ext4_sblock *sb = &inode_ref->fs->sb;
1154 /* Compute next block index and allocate data block */
1155 uint64_t inode_size = ext4_inode_get_size(sb, inode_ref->inode);
1156 uint32_t block_size = ext4_sb_get_block_size(sb);
1158 /* Align size i-node size */
1159 if ((inode_size % block_size) != 0)
1160 inode_size += block_size - (inode_size % block_size);
1162 /* Logical blocks are numbered from 0 */
1163 uint32_t new_block_idx = inode_size / block_size;
1165 /* Allocate new physical block */
1166 uint32_t phys_block;
1167 int rc = ext4_balloc_alloc_block(inode_ref, &phys_block);
1171 /* Add physical block address to the i-node */
1172 rc = ext4_fs_set_inode_data_block_index(inode_ref,
1173 new_block_idx, phys_block);
1175 ext4_balloc_free_block(inode_ref, phys_block);
1180 ext4_inode_set_size(inode_ref->inode, inode_size + block_size);
1181 inode_ref->dirty = true;
1183 *fblock = phys_block;
1184 *iblock = new_block_idx;