static void reserve_indirect_block(struct block_allocation *alloc, int len) { if (reserve_oob_blocks(alloc, 1)) { error("failed to reserve oob block"); return; } if (advance_blocks(alloc, len)) { error("failed to advance %d blocks", len); return; } }
static void reserve_tindirect_block(struct block_allocation *alloc, int len) { if (reserve_oob_blocks(alloc, 1)) { error("failed to reserve oob block"); return; } while (len > 0) { int dind_block_len = min((int)aux_info.blocks_per_dind, len); reserve_dindirect_block(alloc, dind_block_len); len -= dind_block_len; } }
static struct block_allocation *do_inode_allocate_extents( struct ext4_inode *inode, u64 len) { u32 block_len = DIV_ROUND_UP(len, info.block_size); struct block_allocation *alloc = allocate_blocks(block_len + 1); u32 extent_block = 0; u32 file_block = 0; struct ext4_extent *extent; u64 blocks; if (alloc == NULL) { error("Failed to allocate %d blocks\n", block_len + 1); return NULL; } int allocation_len = block_allocation_num_regions(alloc); if (allocation_len <= 3) { reduce_allocation(alloc, 1); } else { reserve_oob_blocks(alloc, 1); extent_block = get_oob_block(alloc, 0); } if (!extent_block) { struct ext4_extent_header *hdr = (struct ext4_extent_header *)&inode->i_block[0]; hdr->eh_magic = EXT4_EXT_MAGIC; hdr->eh_entries = allocation_len; hdr->eh_max = 3; hdr->eh_generation = 0; hdr->eh_depth = 0; extent = (struct ext4_extent *)&inode->i_block[3]; } else { struct ext4_extent_header *hdr = (struct ext4_extent_header *)&inode->i_block[0]; hdr->eh_magic = EXT4_EXT_MAGIC; hdr->eh_entries = 1; hdr->eh_max = 3; hdr->eh_generation = 0; hdr->eh_depth = 1; struct ext4_extent_idx *idx = (struct ext4_extent_idx *)&inode->i_block[3]; idx->ei_block = 0; idx->ei_leaf_lo = extent_block; idx->ei_leaf_hi = 0; idx->ei_unused = 0; u8 *data = calloc(info.block_size, 1); if (!data) critical_error_errno("calloc"); queue_data_block(data, info.block_size, extent_block); if (((int)(info.block_size - sizeof(struct ext4_extent_header) / sizeof(struct ext4_extent))) < allocation_len) { error("File size %llu is too big to fit in a single extent block\n", len); return NULL; } hdr = (struct ext4_extent_header *)data; hdr->eh_magic = EXT4_EXT_MAGIC; hdr->eh_entries = allocation_len; hdr->eh_max = (info.block_size - sizeof(struct ext4_extent_header)) / sizeof(struct ext4_extent); hdr->eh_generation = 0; hdr->eh_depth = 0; extent = (struct ext4_extent *)(data + sizeof(struct ext4_extent_header)); } for (; !last_region(alloc); extent++, get_next_region(alloc)) { u32 region_block; u32 region_len; get_region(alloc, ®ion_block, ®ion_len); extent->ee_block = file_block; extent->ee_len = region_len; extent->ee_start_hi = 0; extent->ee_start_lo = region_block; file_block += region_len; } if (extent_block) block_len += 1; blocks = (u64)block_len * info.block_size / 512; inode->i_flags |= EXT4_EXTENTS_FL; inode->i_size_lo = len; inode->i_size_high = len >> 32; inode->i_blocks_lo = blocks; inode->osd2.linux2.l_i_blocks_high = blocks >> 32; rewind_alloc(alloc); return alloc; }