X-Git-Url: http://git.osdn.net/view?a=blobdiff_plain;f=ext4_utils%2Fextent.c;h=78874882fddb7d58fda5c18f9c036ab9ea57588f;hb=187816e5793ad177f6f70fe6270baf1475d74149;hp=1900b1044a1a44213405f3807d973aca1959b5f0;hpb=946b1184aabba0f1c5809ed7e6b63738145ba421;p=android-x86%2Fsystem-extras.git diff --git a/ext4_utils/extent.c b/ext4_utils/extent.c index 1900b104..78874882 100644 --- a/ext4_utils/extent.c +++ b/ext4_utils/extent.c @@ -5,7 +5,7 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -72,23 +72,43 @@ static void extent_create_backing_file(struct block_allocation *alloc, } static struct block_allocation *do_inode_allocate_extents( - struct ext4_inode *inode, u64 len) + struct ext4_inode *inode, u64 len, struct block_allocation *prealloc) { - u32 block_len = DIV_ROUND_UP(len, info.block_size); - struct block_allocation *alloc = allocate_blocks(block_len + 1); + u32 block_len = DIV_ROUND_UP(len, info.block_size), prealloc_block_len; + struct block_allocation *alloc; u32 extent_block = 0; u32 file_block = 0; struct ext4_extent *extent; u64 blocks; - if (alloc == NULL) { - error("Failed to allocate %d blocks\n", block_len + 1); - return NULL; + if (!prealloc) { + alloc = allocate_blocks(block_len + 1); + if (alloc == NULL) { + error("Failed to allocate %d blocks\n", block_len + 1); + return NULL; + } + } else { + prealloc_block_len = block_allocation_len(prealloc); + if (block_len + 1 > prealloc_block_len) { + alloc = allocate_blocks(block_len + 1 - prealloc_block_len); + if (alloc == NULL) { + error("Failed to allocate %d blocks\n", + block_len + 1 - prealloc_block_len); + return NULL; + } + region_list_merge(&prealloc->list, &alloc->list); + free(alloc); + } + alloc = prealloc; } int allocation_len = block_allocation_num_regions(alloc); if (allocation_len <= 3) { reduce_allocation(alloc, 1); + // IMPORTANT: reduce_allocation may have changed allocation + // length, otherwise file corruption happens when fs thinks + // a block is missing from extent header. + allocation_len = block_allocation_num_regions(alloc); } else { reserve_oob_blocks(alloc, 1); extent_block = get_oob_block(alloc, 0); @@ -183,7 +203,7 @@ u8 *inode_allocate_data_extents(struct ext4_inode *inode, u64 len, struct block_allocation *alloc; u8 *data = NULL; - alloc = do_inode_allocate_extents(inode, len); + alloc = do_inode_allocate_extents(inode, len, NULL); if (alloc == NULL) { error("failed to allocate extents for %"PRIu64" bytes", len); return NULL; @@ -205,9 +225,26 @@ u8 *inode_allocate_data_extents(struct ext4_inode *inode, u64 len, struct block_allocation* inode_allocate_file_extents(struct ext4_inode *inode, u64 len, const char *filename) { - struct block_allocation *alloc; + struct block_allocation *alloc, *prealloc = base_fs_allocations, *prev_prealloc = NULL; + // TODO(mkayyash): base_fs_allocations is sorted by filename, consider + // storing it in an array and then binary searching for a filename match instead + while (prealloc && prealloc->filename != NULL) { + if (!strcmp(filename, prealloc->filename)) { + break; + } + prev_prealloc = prealloc; + prealloc = prealloc->next; + } + if (prealloc) { + if (!prev_prealloc) { + base_fs_allocations = base_fs_allocations->next; + } else { + prev_prealloc->next = prealloc->next; + } + prealloc->next = NULL; + } - alloc = do_inode_allocate_extents(inode, len); + alloc = do_inode_allocate_extents(inode, len, prealloc); if (alloc == NULL) { error("failed to allocate extents for %"PRIu64" bytes", len); return NULL; @@ -222,7 +259,7 @@ void inode_allocate_extents(struct ext4_inode *inode, u64 len) { struct block_allocation *alloc; - alloc = do_inode_allocate_extents(inode, len); + alloc = do_inode_allocate_extents(inode, len, NULL); if (alloc == NULL) { error("failed to allocate extents for %"PRIu64" bytes", len); return;