15a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner/*
25a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner * Copyright (C) 2010 The Android Open Source Project
35a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner *
45a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner * Licensed under the Apache License, Version 2.0 (the "License");
55a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner * you may not use this file except in compliance with the License.
65a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner * You may obtain a copy of the License at
75a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner *
85a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner *      http://www.apache.org/licenses/LICENSE-2.0
95a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner *
105a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner * Unless required by applicable law or agreed to in writing, software
115a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner * distributed under the License is distributed on an "AS IS" BASIS,
125a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
135a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner * See the License for the specific language governing permissions and
145a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner * limitations under the License.
155a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner */
165a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
175a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner#include "ext4_utils.h"
185a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner#include "indirect.h"
195a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner#include "allocate.h"
205a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
215a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner#include <sparse/sparse.h>
225a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
235a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner#include <stdlib.h>
245a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner#include <stdio.h>
255a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
265a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner/* Creates data buffers for the first backing_len bytes of a block allocation
275a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner   and queues them to be written */
285a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turnerstatic u8 *create_backing(struct block_allocation *alloc,
295a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		unsigned long backing_len)
305a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner{
315a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	if (DIV_ROUND_UP(backing_len, info.block_size) > EXT4_NDIR_BLOCKS)
325a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		critical_error("indirect backing larger than %d blocks", EXT4_NDIR_BLOCKS);
335a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
345a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	u8 *data = calloc(backing_len, 1);
355a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	if (!data)
365a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		critical_error_errno("calloc");
375a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
385a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	u8 *ptr = data;
395a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	for (; alloc != NULL && backing_len > 0; get_next_region(alloc)) {
405a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		u32 region_block;
415a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		u32 region_len;
425a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		u32 len;
435a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		get_region(alloc, &region_block, &region_len);
445a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
455a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		len = min(region_len * info.block_size, backing_len);
465a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
475a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		sparse_file_add_data(ext4_sparse_file, ptr, len, region_block);
485a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		ptr += len;
495a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		backing_len -= len;
505a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	}
515a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
525a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	return data;
535a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner}
545a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
555a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turnerstatic void reserve_indirect_block(struct block_allocation *alloc, int len)
565a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner{
575a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	if (reserve_oob_blocks(alloc, 1)) {
585a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		error("failed to reserve oob block");
595a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		return;
605a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	}
615a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
625a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	if (advance_blocks(alloc, len)) {
635a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		error("failed to advance %d blocks", len);
645a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		return;
655a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	}
665a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner}
675a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
685a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turnerstatic void reserve_dindirect_block(struct block_allocation *alloc, int len)
695a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner{
705a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	if (reserve_oob_blocks(alloc, 1)) {
715a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		error("failed to reserve oob block");
725a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		return;
735a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	}
745a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
755a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	while (len > 0) {
765a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		int ind_block_len = min((int)aux_info.blocks_per_ind, len);
775a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
785a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		reserve_indirect_block(alloc, ind_block_len);
795a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
805a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		len -= ind_block_len;
815a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	}
825a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
835a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner}
845a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
855a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turnerstatic void reserve_tindirect_block(struct block_allocation *alloc, int len)
865a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner{
875a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	if (reserve_oob_blocks(alloc, 1)) {
885a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		error("failed to reserve oob block");
895a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		return;
905a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	}
915a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
925a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	while (len > 0) {
935a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		int dind_block_len = min((int)aux_info.blocks_per_dind, len);
945a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
955a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		reserve_dindirect_block(alloc, dind_block_len);
965a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
975a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		len -= dind_block_len;
985a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	}
995a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner}
1005a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
1015a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turnerstatic void fill_indirect_block(u32 *ind_block, int len, struct block_allocation *alloc)
1025a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner{
1035a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	int i;
1045a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	for (i = 0; i < len; i++) {
1055a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		ind_block[i] = get_block(alloc, i);
1065a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	}
1075a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner}
1085a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
1095a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turnerstatic void fill_dindirect_block(u32 *dind_block, int len, struct block_allocation *alloc)
1105a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner{
1115a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	int i;
1125a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	u32 ind_block;
1135a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
1145a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	for (i = 0; len >  0; i++) {
1155a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		ind_block = get_oob_block(alloc, 0);
1165a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		if (advance_oob_blocks(alloc, 1)) {
1175a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner			error("failed to reserve oob block");
1185a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner			return;
1195a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		}
1205a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
1215a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		dind_block[i] = ind_block;
1225a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
1235a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		u32 *ind_block_data = calloc(info.block_size, 1);
1245a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		sparse_file_add_data(ext4_sparse_file, ind_block_data, info.block_size,
1255a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner				ind_block);
1265a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		int ind_block_len = min((int)aux_info.blocks_per_ind, len);
1275a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
1285a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		fill_indirect_block(ind_block_data, ind_block_len, alloc);
1295a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
1305a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		if (advance_blocks(alloc, ind_block_len)) {
1315a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner			error("failed to advance %d blocks", ind_block_len);
1325a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner			return;
1335a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		}
1345a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
1355a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		len -= ind_block_len;
1365a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	}
1375a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner}
1385a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
1395a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turnerstatic void fill_tindirect_block(u32 *tind_block, int len, struct block_allocation *alloc)
1405a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner{
1415a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	int i;
1425a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	u32 dind_block;
1435a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
1445a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	for (i = 0; len > 0; i++) {
1455a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		dind_block = get_oob_block(alloc, 0);
1465a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		if (advance_oob_blocks(alloc, 1)) {
1475a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner			error("failed to reserve oob block");
1485a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner			return;
1495a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		}
1505a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
1515a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		tind_block[i] = dind_block;
1525a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
1535a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		u32 *dind_block_data = calloc(info.block_size, 1);
1545a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		sparse_file_add_data(ext4_sparse_file, dind_block_data, info.block_size,
1555a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner				dind_block);
1565a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		int dind_block_len = min((int)aux_info.blocks_per_dind, len);
1575a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
1585a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		fill_dindirect_block(dind_block_data, dind_block_len, alloc);
1595a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
1605a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		len -= dind_block_len;
1615a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	}
1625a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner}
1635a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
1645a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner/* Given an allocation, attach as many blocks as possible to direct inode
1655a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner   blocks, and return the rest */
1665a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turnerstatic int inode_attach_direct_blocks(struct ext4_inode *inode,
1675a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		struct block_allocation *alloc, u32 *block_len)
1685a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner{
1695a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	int len = min(*block_len, EXT4_NDIR_BLOCKS);
1705a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	int i;
1715a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
1725a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	for (i = 0; i < len; i++) {
1735a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		inode->i_block[i] = get_block(alloc, i);
1745a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	}
1755a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
1765a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	if (advance_blocks(alloc, len)) {
1775a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		error("failed to advance %d blocks", len);
1785a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		return -1;
1795a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	}
1805a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
1815a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	*block_len -= len;
1825a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	return 0;
1835a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner}
1845a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
1855a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner/* Given an allocation, attach as many blocks as possible to indirect blocks,
1865a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner   and return the rest
1875a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner   Assumes that the blocks necessary to hold the indirect blocks were included
1885a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner   as part of the allocation */
1895a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turnerstatic int inode_attach_indirect_blocks(struct ext4_inode *inode,
1905a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		struct block_allocation *alloc, u32 *block_len)
1915a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner{
1925a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	int len = min(*block_len, aux_info.blocks_per_ind);
1935a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
1945a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	int ind_block = get_oob_block(alloc, 0);
1955a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	inode->i_block[EXT4_IND_BLOCK] = ind_block;
1965a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
1975a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	if (advance_oob_blocks(alloc, 1)) {
1985a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		error("failed to advance oob block");
1995a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		return -1;
2005a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	}
2015a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
2025a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	u32 *ind_block_data = calloc(info.block_size, 1);
2035a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	sparse_file_add_data(ext4_sparse_file, ind_block_data, info.block_size,
2045a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner			ind_block);
2055a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
2065a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	fill_indirect_block(ind_block_data, len, alloc);
2075a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
2085a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	if (advance_blocks(alloc, len)) {
2095a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		error("failed to advance %d blocks", len);
2105a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		return -1;
2115a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	}
2125a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
2135a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	*block_len -= len;
2145a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	return 0;
2155a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner}
2165a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
2175a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner/* Given an allocation, attach as many blocks as possible to doubly indirect
2185a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner   blocks, and return the rest.
2195a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner   Assumes that the blocks necessary to hold the indirect and doubly indirect
2205a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner   blocks were included as part of the allocation */
2215a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turnerstatic int inode_attach_dindirect_blocks(struct ext4_inode *inode,
2225a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		struct block_allocation *alloc, u32 *block_len)
2235a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner{
2245a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	int len = min(*block_len, aux_info.blocks_per_dind);
2255a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
2265a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	int dind_block = get_oob_block(alloc, 0);
2275a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	inode->i_block[EXT4_DIND_BLOCK] = dind_block;
2285a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
2295a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	if (advance_oob_blocks(alloc, 1)) {
2305a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		error("failed to advance oob block");
2315a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		return -1;
2325a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	}
2335a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
2345a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	u32 *dind_block_data = calloc(info.block_size, 1);
2355a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	sparse_file_add_data(ext4_sparse_file, dind_block_data, info.block_size,
2365a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner			dind_block);
2375a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
2385a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	fill_dindirect_block(dind_block_data, len, alloc);
2395a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
2405a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	if (advance_blocks(alloc, len)) {
2415a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		error("failed to advance %d blocks", len);
2425a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		return -1;
2435a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	}
2445a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
2455a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	*block_len -= len;
2465a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	return 0;
2475a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner}
2485a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
2495a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner/* Given an allocation, attach as many blocks as possible to triply indirect
2505a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner   blocks, and return the rest.
2515a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner   Assumes that the blocks necessary to hold the indirect, doubly indirect and
2525a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner   triply indirect blocks were included as part of the allocation */
2535a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turnerstatic int inode_attach_tindirect_blocks(struct ext4_inode *inode,
2545a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		struct block_allocation *alloc, u32 *block_len)
2555a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner{
2565a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	int len = min(*block_len, aux_info.blocks_per_tind);
2575a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
2585a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	int tind_block = get_oob_block(alloc, 0);
2595a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	inode->i_block[EXT4_TIND_BLOCK] = tind_block;
2605a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
2615a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	if (advance_oob_blocks(alloc, 1)) {
2625a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		error("failed to advance oob block");
2635a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		return -1;
2645a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	}
2655a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
2665a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	u32 *tind_block_data = calloc(info.block_size, 1);
2675a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	sparse_file_add_data(ext4_sparse_file, tind_block_data, info.block_size,
2685a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner			tind_block);
2695a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
2705a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	fill_tindirect_block(tind_block_data, len, alloc);
2715a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
2725a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	if (advance_blocks(alloc, len)) {
2735a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		error("failed to advance %d blocks", len);
2745a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		return -1;
2755a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	}
2765a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
2775a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	*block_len -= len;
2785a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	return 0;
2795a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner}
2805a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
2815a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turnerstatic void reserve_all_indirect_blocks(struct block_allocation *alloc, u32 len)
2825a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner{
2835a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	if (len <= EXT4_NDIR_BLOCKS)
2845a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		return;
2855a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
2865a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	len -= EXT4_NDIR_BLOCKS;
2875a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	advance_blocks(alloc, EXT4_NDIR_BLOCKS);
2885a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
2895a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	u32 ind_block_len = min(aux_info.blocks_per_ind, len);
2905a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	reserve_indirect_block(alloc, ind_block_len);
2915a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
2925a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	len -= ind_block_len;
2935a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	if (len == 0)
2945a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		return;
2955a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
2965a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	u32 dind_block_len = min(aux_info.blocks_per_dind, len);
2975a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	reserve_dindirect_block(alloc, dind_block_len);
2985a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
2995a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	len -= dind_block_len;
3005a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	if (len == 0)
3015a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		return;
3025a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
3035a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	u32 tind_block_len = min(aux_info.blocks_per_tind, len);
3045a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	reserve_tindirect_block(alloc, tind_block_len);
3055a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
3065a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	len -= tind_block_len;
3075a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	if (len == 0)
3085a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		return;
3095a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
3105a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	error("%d blocks remaining", len);
3115a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner}
3125a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
3135a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turnerstatic u32 indirect_blocks_needed(u32 len)
3145a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner{
3155a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	u32 ind = 0;
3165a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
3175a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	if (len <= EXT4_NDIR_BLOCKS)
3185a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		return ind;
3195a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
3205a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	len -= EXT4_NDIR_BLOCKS;
3215a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
3225a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	/* We will need an indirect block for the rest of the blocks */
3235a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	ind += DIV_ROUND_UP(len, aux_info.blocks_per_ind);
3245a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
3255a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	if (len <= aux_info.blocks_per_ind)
3265a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		return ind;
3275a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
3285a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	len -= aux_info.blocks_per_ind;
3295a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
3305a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	ind += DIV_ROUND_UP(len, aux_info.blocks_per_dind);
3315a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
3325a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	if (len <= aux_info.blocks_per_dind)
3335a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		return ind;
3345a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
3355a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	len -= aux_info.blocks_per_dind;
3365a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
3375a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	ind += DIV_ROUND_UP(len, aux_info.blocks_per_tind);
3385a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
3395a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	if (len <= aux_info.blocks_per_tind)
3405a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		return ind;
3415a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
3425a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	critical_error("request too large");
3435a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	return 0;
3445a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner}
3455a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
3465a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turnerstatic int do_inode_attach_indirect(struct ext4_inode *inode,
3475a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		struct block_allocation *alloc, u32 block_len)
3485a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner{
3495a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	u32 count = block_len;
3505a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
3515a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	if (inode_attach_direct_blocks(inode, alloc, &count)) {
3525a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		error("failed to attach direct blocks to inode");
3535a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		return -1;
3545a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	}
3555a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
3565a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	if (count > 0) {
3575a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		if (inode_attach_indirect_blocks(inode, alloc, &count)) {
3585a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner			error("failed to attach indirect blocks to inode");
3595a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner			return -1;
3605a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		}
3615a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	}
3625a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
3635a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	if (count > 0) {
3645a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		if (inode_attach_dindirect_blocks(inode, alloc, &count)) {
3655a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner			error("failed to attach dindirect blocks to inode");
3665a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner			return -1;
3675a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		}
3685a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	}
3695a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
3705a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	if (count > 0) {
3715a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		if (inode_attach_tindirect_blocks(inode, alloc, &count)) {
3725a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner			error("failed to attach tindirect blocks to inode");
3735a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner			return -1;
3745a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		}
3755a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	}
3765a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
3775a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	if (count) {
3785a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		error("blocks left after triply-indirect allocation");
3795a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		return -1;
3805a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	}
3815a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
3825a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	rewind_alloc(alloc);
3835a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
3845a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	return 0;
3855a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner}
3865a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
3875a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turnerstatic struct block_allocation *do_inode_allocate_indirect(
3885a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		u32 block_len)
3895a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner{
3905a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	u32 indirect_len = indirect_blocks_needed(block_len);
3915a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
3925a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	struct block_allocation *alloc = allocate_blocks(block_len + indirect_len);
3935a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
3945a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	if (alloc == NULL) {
3955a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		error("Failed to allocate %d blocks", block_len + indirect_len);
3965a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		return NULL;
3975a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	}
3985a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
3995a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	return alloc;
4005a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner}
4015a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
4025a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner/* Allocates enough blocks to hold len bytes and connects them to an inode */
4035a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turnervoid inode_allocate_indirect(struct ext4_inode *inode, unsigned long len)
4045a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner{
4055a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	struct block_allocation *alloc;
4065a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	u32 block_len = DIV_ROUND_UP(len, info.block_size);
4075a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	u32 indirect_len = indirect_blocks_needed(block_len);
4085a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
4095a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	alloc = do_inode_allocate_indirect(block_len);
4105a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	if (alloc == NULL) {
4115a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		error("failed to allocate extents for %lu bytes", len);
4125a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		return;
4135a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	}
4145a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
4155a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	reserve_all_indirect_blocks(alloc, block_len);
4165a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	rewind_alloc(alloc);
4175a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
4185a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	if (do_inode_attach_indirect(inode, alloc, block_len))
4195a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		error("failed to attach blocks to indirect inode");
4205a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
4215a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	inode->i_flags = 0;
4225a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	inode->i_blocks_lo = (block_len + indirect_len) * info.block_size / 512;
4235a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	inode->i_size_lo = len;
4245a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
4255a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	free_alloc(alloc);
4265a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner}
4275a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
4285a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turnervoid inode_attach_resize(struct ext4_inode *inode,
4295a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		struct block_allocation *alloc)
4305a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner{
4315a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	u32 block_len = block_allocation_len(alloc);
4325a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	u32 superblocks = block_len / info.bg_desc_reserve_blocks;
4335a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	u32 i, j;
4345a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	u64 blocks;
4355a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	u64 size;
4365a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
4375a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	if (block_len % info.bg_desc_reserve_blocks)
4385a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		critical_error("reserved blocks not a multiple of %d",
4395a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner				info.bg_desc_reserve_blocks);
4405a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
4415a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	append_oob_allocation(alloc, 1);
4425a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	u32 dind_block = get_oob_block(alloc, 0);
4435a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
4445a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	u32 *dind_block_data = calloc(info.block_size, 1);
4455a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	if (!dind_block_data)
4465a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		critical_error_errno("calloc");
4475a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	sparse_file_add_data(ext4_sparse_file, dind_block_data, info.block_size,
4485a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner			dind_block);
4495a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
4505a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	u32 *ind_block_data = calloc(info.block_size, info.bg_desc_reserve_blocks);
4515a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	if (!ind_block_data)
4525a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		critical_error_errno("calloc");
4535a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	sparse_file_add_data(ext4_sparse_file, ind_block_data,
4545a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner			info.block_size * info.bg_desc_reserve_blocks,
4555a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner			get_block(alloc, 0));
4565a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
4575a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	for (i = 0; i < info.bg_desc_reserve_blocks; i++) {
4585a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		int r = (i - aux_info.bg_desc_blocks) % info.bg_desc_reserve_blocks;
4595a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		if (r < 0)
4605a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner			r += info.bg_desc_reserve_blocks;
4615a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
4625a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		dind_block_data[i] = get_block(alloc, r);
4635a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
4645a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		for (j = 1; j < superblocks; j++) {
4655a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner			u32 b = j * info.bg_desc_reserve_blocks + r;
4665a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner			ind_block_data[r * aux_info.blocks_per_ind + j - 1] = get_block(alloc, b);
4675a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		}
4685a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	}
4695a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
4705a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	u32 last_block = EXT4_NDIR_BLOCKS + aux_info.blocks_per_ind +
4715a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner			aux_info.blocks_per_ind * (info.bg_desc_reserve_blocks - 1) +
4725a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner			superblocks - 2;
4735a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
4745a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	blocks = ((u64)block_len + 1) * info.block_size / 512;
4755a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	size = (u64)last_block * info.block_size;
4765a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
4775a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	inode->i_block[EXT4_DIND_BLOCK] = dind_block;
4785a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	inode->i_flags = 0;
4795a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	inode->i_blocks_lo = blocks;
4805a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	inode->osd2.linux2.l_i_blocks_high = blocks >> 32;
4815a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	inode->i_size_lo = size;
4825a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	inode->i_size_high = size >> 32;
4835a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner}
4845a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
4855a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner/* Allocates enough blocks to hold len bytes, with backing_len bytes in a data
4865a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner   buffer, and connects them to an inode.  Returns a pointer to the data
4875a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner   buffer. */
4885a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turneru8 *inode_allocate_data_indirect(struct ext4_inode *inode, unsigned long len,
4895a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		unsigned long backing_len)
4905a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner{
4915a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	struct block_allocation *alloc;
4925a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	u32 block_len = DIV_ROUND_UP(len, info.block_size);
4935a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	u8 *data = NULL;
4945a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
4955a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	alloc = do_inode_allocate_indirect(block_len);
4965a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	if (alloc == NULL) {
4975a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		error("failed to allocate extents for %lu bytes", len);
4985a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		return NULL;
4995a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	}
5005a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
5015a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	if (backing_len) {
5025a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		data = create_backing(alloc, backing_len);
5035a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		if (!data)
5045a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner			error("failed to create backing for %lu bytes", backing_len);
5055a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	}
5065a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
5075a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	rewind_alloc(alloc);
5085a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	if (do_inode_attach_indirect(inode, alloc, block_len))
5095a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner		error("failed to attach blocks to indirect inode");
5105a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
5115a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	free_alloc(alloc);
5125a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner
5135a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner	return data;
5145a60dc51ef5c2b97db192244e79b12ad03ee885eDavid 'Digit' Turner}
515