Example #1
0
/* Allocates enough blocks to hold len bytes, with backing_len bytes in a data
   buffer, and connects them to an inode.  Returns a pointer to the data
   buffer. */
u8 *inode_allocate_data_indirect(struct ext4_inode *inode, unsigned long len,
		unsigned long backing_len)
{
	struct block_allocation *alloc;
	u32 block_len = DIV_ROUND_UP(len, info.block_size);
	u8 *data = NULL;

	alloc = do_inode_allocate_indirect(inode, block_len);
	if (alloc == NULL) {
		error("failed to allocate extents for %lu bytes", len);
		return NULL;
	}

	if (backing_len) {
		data = create_backing(alloc, backing_len);
		if (!data)
			error("failed to create backing for %lu bytes", backing_len);
	}

	rewind_alloc(alloc);
	if (do_inode_attach_indirect(inode, alloc, block_len))
		error("failed to attach blocks to indirect inode");

	free_alloc(alloc);

	return data;
}
Example #2
0
static int do_inode_attach_indirect(struct ext4_inode *inode,
		struct block_allocation *alloc, u32 block_len)
{
	u32 count = block_len;

	if (inode_attach_direct_blocks(inode, alloc, &count)) {
		error("failed to attach direct blocks to inode");
		return -1;
	}

	if (count > 0) {
		if (inode_attach_indirect_blocks(inode, alloc, &count)) {
			error("failed to attach indirect blocks to inode");
			return -1;
		}
	}

	if (count > 0) {
		if (inode_attach_dindirect_blocks(inode, alloc, &count)) {
			error("failed to attach dindirect blocks to inode");
			return -1;
		}
	}

	if (count > 0) {
		if (inode_attach_tindirect_blocks(inode, alloc, &count)) {
			error("failed to attach tindirect blocks to inode");
			return -1;
		}
	}

	if (count) {
		error("blocks left after triply-indirect allocation");
		return -1;
	}

	rewind_alloc(alloc);

	return 0;
}
Example #3
0
/* Allocates enough blocks to hold len bytes and connects them to an inode */
void inode_allocate_indirect(struct ext4_inode *inode, unsigned long len)
{
	struct block_allocation *alloc;
	u32 block_len = DIV_ROUND_UP(len, info.block_size);
	u32 indirect_len = indirect_blocks_needed(block_len);

	alloc = do_inode_allocate_indirect(inode, block_len);
	if (alloc == NULL) {
		error("failed to allocate extents for %lu bytes", len);
		return;
	}

	reserve_all_indirect_blocks(alloc, block_len);
	rewind_alloc(alloc);

	if (do_inode_attach_indirect(inode, alloc, block_len))
		error("failed to attach blocks to indirect inode");

	inode->i_flags = 0;
	inode->i_blocks_lo = (block_len + indirect_len) * info.block_size / 512;
	inode->i_size_lo = len;

	free_alloc(alloc);
}
Example #4
0
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, &region_block, &region_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;
}