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, ®ion_block, ®ion_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