2 * Copyright (C) 2010 The Android Open Source Project
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
22 #include <sparse/sparse.h>
25 #include "ext4_utils/ext4_utils.h"
28 /* Creates data buffers for the first backing_len bytes of a block allocation
29 and queues them to be written */
30 static u8 *create_backing(struct block_allocation *alloc,
31 unsigned long backing_len)
33 if (DIV_ROUND_UP(backing_len, info.block_size) > EXT4_NDIR_BLOCKS)
34 critical_error("indirect backing larger than %d blocks", EXT4_NDIR_BLOCKS);
36 u8 *data = calloc(backing_len, 1);
38 critical_error_errno("calloc");
41 for (; alloc != NULL && backing_len > 0; get_next_region(alloc)) {
45 get_region(alloc, ®ion_block, ®ion_len);
47 len = min(region_len * info.block_size, backing_len);
49 sparse_file_add_data(ext4_sparse_file, ptr, len, region_block);
57 static void reserve_indirect_block(struct block_allocation *alloc, int len)
59 if (reserve_oob_blocks(alloc, 1)) {
60 error("failed to reserve oob block");
64 if (advance_blocks(alloc, len)) {
65 error("failed to advance %d blocks", len);
70 static void reserve_dindirect_block(struct block_allocation *alloc, int len)
72 if (reserve_oob_blocks(alloc, 1)) {
73 error("failed to reserve oob block");
78 int ind_block_len = min((int)aux_info.blocks_per_ind, len);
80 reserve_indirect_block(alloc, ind_block_len);
87 static void reserve_tindirect_block(struct block_allocation *alloc, int len)
89 if (reserve_oob_blocks(alloc, 1)) {
90 error("failed to reserve oob block");
95 int dind_block_len = min((int)aux_info.blocks_per_dind, len);
97 reserve_dindirect_block(alloc, dind_block_len);
99 len -= dind_block_len;
103 static void fill_indirect_block(u32 *ind_block, int len, struct block_allocation *alloc)
106 for (i = 0; i < len; i++) {
107 ind_block[i] = get_block(alloc, i);
111 static void fill_dindirect_block(u32 *dind_block, int len, struct block_allocation *alloc)
116 for (i = 0; len > 0; i++) {
117 ind_block = get_oob_block(alloc, 0);
118 if (advance_oob_blocks(alloc, 1)) {
119 error("failed to reserve oob block");
123 dind_block[i] = ind_block;
125 u32 *ind_block_data = calloc(info.block_size, 1);
126 sparse_file_add_data(ext4_sparse_file, ind_block_data, info.block_size,
128 int ind_block_len = min((int)aux_info.blocks_per_ind, len);
130 fill_indirect_block(ind_block_data, ind_block_len, alloc);
132 if (advance_blocks(alloc, ind_block_len)) {
133 error("failed to advance %d blocks", ind_block_len);
137 len -= ind_block_len;
141 static void fill_tindirect_block(u32 *tind_block, int len, struct block_allocation *alloc)
146 for (i = 0; len > 0; i++) {
147 dind_block = get_oob_block(alloc, 0);
148 if (advance_oob_blocks(alloc, 1)) {
149 error("failed to reserve oob block");
153 tind_block[i] = dind_block;
155 u32 *dind_block_data = calloc(info.block_size, 1);
156 sparse_file_add_data(ext4_sparse_file, dind_block_data, info.block_size,
158 int dind_block_len = min((int)aux_info.blocks_per_dind, len);
160 fill_dindirect_block(dind_block_data, dind_block_len, alloc);
162 len -= dind_block_len;
166 /* Given an allocation, attach as many blocks as possible to direct inode
167 blocks, and return the rest */
168 static int inode_attach_direct_blocks(struct ext4_inode *inode,
169 struct block_allocation *alloc, u32 *block_len)
171 int len = min(*block_len, EXT4_NDIR_BLOCKS);
174 for (i = 0; i < len; i++) {
175 inode->i_block[i] = get_block(alloc, i);
178 if (advance_blocks(alloc, len)) {
179 error("failed to advance %d blocks", len);
187 /* Given an allocation, attach as many blocks as possible to indirect blocks,
189 Assumes that the blocks necessary to hold the indirect blocks were included
190 as part of the allocation */
191 static int inode_attach_indirect_blocks(struct ext4_inode *inode,
192 struct block_allocation *alloc, u32 *block_len)
194 int len = min(*block_len, aux_info.blocks_per_ind);
196 int ind_block = get_oob_block(alloc, 0);
197 inode->i_block[EXT4_IND_BLOCK] = ind_block;
199 if (advance_oob_blocks(alloc, 1)) {
200 error("failed to advance oob block");
204 u32 *ind_block_data = calloc(info.block_size, 1);
205 sparse_file_add_data(ext4_sparse_file, ind_block_data, info.block_size,
208 fill_indirect_block(ind_block_data, len, alloc);
210 if (advance_blocks(alloc, len)) {
211 error("failed to advance %d blocks", len);
219 /* Given an allocation, attach as many blocks as possible to doubly indirect
220 blocks, and return the rest.
221 Assumes that the blocks necessary to hold the indirect and doubly indirect
222 blocks were included as part of the allocation */
223 static int inode_attach_dindirect_blocks(struct ext4_inode *inode,
224 struct block_allocation *alloc, u32 *block_len)
226 int len = min(*block_len, aux_info.blocks_per_dind);
228 int dind_block = get_oob_block(alloc, 0);
229 inode->i_block[EXT4_DIND_BLOCK] = dind_block;
231 if (advance_oob_blocks(alloc, 1)) {
232 error("failed to advance oob block");
236 u32 *dind_block_data = calloc(info.block_size, 1);
237 sparse_file_add_data(ext4_sparse_file, dind_block_data, info.block_size,
240 fill_dindirect_block(dind_block_data, len, alloc);
242 if (advance_blocks(alloc, len)) {
243 error("failed to advance %d blocks", len);
251 /* Given an allocation, attach as many blocks as possible to triply indirect
252 blocks, and return the rest.
253 Assumes that the blocks necessary to hold the indirect, doubly indirect and
254 triply indirect blocks were included as part of the allocation */
255 static int inode_attach_tindirect_blocks(struct ext4_inode *inode,
256 struct block_allocation *alloc, u32 *block_len)
258 int len = min(*block_len, aux_info.blocks_per_tind);
260 int tind_block = get_oob_block(alloc, 0);
261 inode->i_block[EXT4_TIND_BLOCK] = tind_block;
263 if (advance_oob_blocks(alloc, 1)) {
264 error("failed to advance oob block");
268 u32 *tind_block_data = calloc(info.block_size, 1);
269 sparse_file_add_data(ext4_sparse_file, tind_block_data, info.block_size,
272 fill_tindirect_block(tind_block_data, len, alloc);
274 if (advance_blocks(alloc, len)) {
275 error("failed to advance %d blocks", len);
283 static void reserve_all_indirect_blocks(struct block_allocation *alloc, u32 len)
285 if (len <= EXT4_NDIR_BLOCKS)
288 len -= EXT4_NDIR_BLOCKS;
289 advance_blocks(alloc, EXT4_NDIR_BLOCKS);
291 u32 ind_block_len = min(aux_info.blocks_per_ind, len);
292 reserve_indirect_block(alloc, ind_block_len);
294 len -= ind_block_len;
298 u32 dind_block_len = min(aux_info.blocks_per_dind, len);
299 reserve_dindirect_block(alloc, dind_block_len);
301 len -= dind_block_len;
305 u32 tind_block_len = min(aux_info.blocks_per_tind, len);
306 reserve_tindirect_block(alloc, tind_block_len);
308 len -= tind_block_len;
312 error("%d blocks remaining", len);
315 static u32 indirect_blocks_needed(u32 len)
319 if (len <= EXT4_NDIR_BLOCKS)
322 len -= EXT4_NDIR_BLOCKS;
324 /* We will need an indirect block for the rest of the blocks */
325 ind += DIV_ROUND_UP(len, aux_info.blocks_per_ind);
327 if (len <= aux_info.blocks_per_ind)
330 len -= aux_info.blocks_per_ind;
332 ind += DIV_ROUND_UP(len, aux_info.blocks_per_dind);
334 if (len <= aux_info.blocks_per_dind)
337 len -= aux_info.blocks_per_dind;
339 ind += DIV_ROUND_UP(len, aux_info.blocks_per_tind);
341 if (len <= aux_info.blocks_per_tind)
344 critical_error("request too large");
348 static int do_inode_attach_indirect(struct ext4_inode *inode,
349 struct block_allocation *alloc, u32 block_len)
351 u32 count = block_len;
353 if (inode_attach_direct_blocks(inode, alloc, &count)) {
354 error("failed to attach direct blocks to inode");
359 if (inode_attach_indirect_blocks(inode, alloc, &count)) {
360 error("failed to attach indirect blocks to inode");
366 if (inode_attach_dindirect_blocks(inode, alloc, &count)) {
367 error("failed to attach dindirect blocks to inode");
373 if (inode_attach_tindirect_blocks(inode, alloc, &count)) {
374 error("failed to attach tindirect blocks to inode");
380 error("blocks left after triply-indirect allocation");
389 static struct block_allocation *do_inode_allocate_indirect(
392 u32 indirect_len = indirect_blocks_needed(block_len);
394 struct block_allocation *alloc = allocate_blocks(block_len + indirect_len);
397 error("Failed to allocate %d blocks", block_len + indirect_len);
404 /* Allocates enough blocks to hold len bytes and connects them to an inode */
405 void inode_allocate_indirect(struct ext4_inode *inode, unsigned long len)
407 struct block_allocation *alloc;
408 u32 block_len = DIV_ROUND_UP(len, info.block_size);
409 u32 indirect_len = indirect_blocks_needed(block_len);
411 alloc = do_inode_allocate_indirect(block_len);
413 error("failed to allocate extents for %lu bytes", len);
417 reserve_all_indirect_blocks(alloc, block_len);
420 if (do_inode_attach_indirect(inode, alloc, block_len))
421 error("failed to attach blocks to indirect inode");
424 inode->i_blocks_lo = (block_len + indirect_len) * info.block_size / 512;
425 inode->i_size_lo = len;
430 void inode_attach_resize(struct ext4_inode *inode,
431 struct block_allocation *alloc)
433 u32 block_len = block_allocation_len(alloc);
434 u32 superblocks = block_len / info.bg_desc_reserve_blocks;
439 if (block_len % info.bg_desc_reserve_blocks)
440 critical_error("reserved blocks not a multiple of %d",
441 info.bg_desc_reserve_blocks);
443 append_oob_allocation(alloc, 1);
444 u32 dind_block = get_oob_block(alloc, 0);
446 u32 *dind_block_data = calloc(info.block_size, 1);
447 if (!dind_block_data)
448 critical_error_errno("calloc");
449 sparse_file_add_data(ext4_sparse_file, dind_block_data, info.block_size,
452 u32 *ind_block_data = calloc(info.block_size, info.bg_desc_reserve_blocks);
454 critical_error_errno("calloc");
455 sparse_file_add_data(ext4_sparse_file, ind_block_data,
456 info.block_size * info.bg_desc_reserve_blocks,
457 get_block(alloc, 0));
459 for (i = 0; i < info.bg_desc_reserve_blocks; i++) {
460 int r = (i - aux_info.bg_desc_blocks) % info.bg_desc_reserve_blocks;
462 r += info.bg_desc_reserve_blocks;
464 dind_block_data[i] = get_block(alloc, r);
466 for (j = 1; j < superblocks; j++) {
467 u32 b = j * info.bg_desc_reserve_blocks + r;
468 ind_block_data[r * aux_info.blocks_per_ind + j - 1] = get_block(alloc, b);
472 u32 last_block = EXT4_NDIR_BLOCKS + aux_info.blocks_per_ind +
473 aux_info.blocks_per_ind * (info.bg_desc_reserve_blocks - 1) +
476 blocks = ((u64)block_len + 1) * info.block_size / 512;
477 size = (u64)last_block * info.block_size;
479 inode->i_block[EXT4_DIND_BLOCK] = dind_block;
481 inode->i_blocks_lo = blocks;
482 inode->osd2.linux2.l_i_blocks_high = blocks >> 32;
483 inode->i_size_lo = size;
484 inode->i_size_high = size >> 32;
487 /* Allocates enough blocks to hold len bytes, with backing_len bytes in a data
488 buffer, and connects them to an inode. Returns a pointer to the data
490 u8 *inode_allocate_data_indirect(struct ext4_inode *inode, unsigned long len,
491 unsigned long backing_len)
493 struct block_allocation *alloc;
494 u32 block_len = DIV_ROUND_UP(len, info.block_size);
497 alloc = do_inode_allocate_indirect(block_len);
499 error("failed to allocate extents for %lu bytes", len);
504 data = create_backing(alloc, backing_len);
506 error("failed to create backing for %lu bytes", backing_len);
510 if (do_inode_attach_indirect(inode, alloc, block_len))
511 error("failed to attach blocks to indirect inode");