void inode_attach_resize(struct ext4_inode *inode, struct block_allocation *alloc) { u32 block_len = block_allocation_len(alloc); u32 superblocks = block_len / info.bg_desc_reserve_blocks; u32 i, j; u64 blocks; u64 size; if (block_len % info.bg_desc_reserve_blocks) critical_error("reserved blocks not a multiple of %d", info.bg_desc_reserve_blocks); append_oob_allocation(alloc, 1); u32 dind_block = get_oob_block(alloc, 0); u32 *dind_block_data = calloc(info.block_size, 1); if (!dind_block_data) critical_error_errno("calloc"); queue_data_block((u8 *)dind_block_data, info.block_size, dind_block); u32 *ind_block_data = calloc(info.block_size, info.bg_desc_reserve_blocks); if (!ind_block_data) critical_error_errno("calloc"); queue_data_block((u8 *)ind_block_data, info.block_size * info.bg_desc_reserve_blocks, get_block(alloc, 0)); for (i = 0; i < info.bg_desc_reserve_blocks; i++) { int r = (i - aux_info.bg_desc_blocks) % info.bg_desc_reserve_blocks; if (r < 0) r += info.bg_desc_reserve_blocks; dind_block_data[i] = get_block(alloc, r); for (j = 1; j < superblocks; j++) { u32 b = j * info.bg_desc_reserve_blocks + r; ind_block_data[r * aux_info.blocks_per_ind + j - 1] = get_block(alloc, b); } } u32 last_block = EXT4_NDIR_BLOCKS + aux_info.blocks_per_ind + aux_info.blocks_per_ind * (info.bg_desc_reserve_blocks - 1) + superblocks - 2; blocks = ((u64)block_len + 1) * info.block_size / 512; size = (u64)last_block * info.block_size; inode->i_block[EXT4_DIND_BLOCK] = dind_block; inode->i_flags = 0; inode->i_blocks_lo = blocks; inode->osd2.linux2.l_i_blocks_high = blocks >> 32; inode->i_size_lo = size; inode->i_size_high = size >> 32; }
static void fill_tindirect_block(u32 *tind_block, int len, struct block_allocation *alloc) { int i; u32 dind_block; for (i = 0; len > 0; i++) { dind_block = get_oob_block(alloc, 0); if (advance_oob_blocks(alloc, 1)) { error("failed to reserve oob block"); return; } tind_block[i] = dind_block; u32 *dind_block_data = calloc(info.block_size, 1); queue_data_block((u8*)dind_block_data, info.block_size, dind_block); int dind_block_len = min((int)aux_info.blocks_per_dind, len); fill_dindirect_block(dind_block_data, dind_block_len, alloc); 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; }