blob: 28fc8e50d50048d03da56cfb7b09cec3f6549b46 [file] [log] [blame]
Colin Crossec0a2e82010-06-11 14:21:37 -07001/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
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
7 *
Mohamad Ayyash95791982016-02-20 03:46:00 +00008 * http://www.apache.org/licenses/LICENSE-2.0
Colin Crossec0a2e82010-06-11 14:21:37 -07009 *
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.
15 */
16
Colin Crossec0a2e82010-06-11 14:21:37 -070017#include "allocate.h"
Colin Crossec0a2e82010-06-11 14:21:37 -070018
Colin Cross33f96c62010-12-22 18:40:14 -080019#include <stdio.h>
20#include <stdlib.h>
21
Tao Bao06ca8112016-10-05 12:44:18 -070022#include <sparse/sparse.h>
23
24#include "ext4_utils/ext4_utils.h"
25
Nick Kralevich4df62f32013-02-07 14:21:34 -080026struct xattr_list_element {
27 struct ext4_inode *inode;
28 struct ext4_xattr_header *header;
29 struct xattr_list_element *next;
30};
31
Colin Crossec0a2e82010-06-11 14:21:37 -070032struct block_allocation *create_allocation()
33{
Colin Cross8aef66d2010-06-20 23:22:12 -070034 struct block_allocation *alloc = malloc(sizeof(struct block_allocation));
35 alloc->list.first = NULL;
36 alloc->list.last = NULL;
37 alloc->oob_list.first = NULL;
38 alloc->oob_list.last = NULL;
39 alloc->list.iter = NULL;
40 alloc->list.partial_iter = 0;
41 alloc->oob_list.iter = NULL;
42 alloc->oob_list.partial_iter = 0;
Doug Zongkerbec598e2014-08-12 11:35:37 -070043 alloc->filename = NULL;
44 alloc->next = NULL;
Colin Cross8aef66d2010-06-20 23:22:12 -070045 return alloc;
Colin Crossec0a2e82010-06-11 14:21:37 -070046}
47
Nick Kralevich4df62f32013-02-07 14:21:34 -080048static struct ext4_xattr_header *xattr_list_find(struct ext4_inode *inode)
49{
50 struct xattr_list_element *element;
51 for (element = aux_info.xattrs; element != NULL; element = element->next) {
52 if (element->inode == inode)
53 return element->header;
54 }
55 return NULL;
56}
57
58static void xattr_list_insert(struct ext4_inode *inode, struct ext4_xattr_header *header)
59{
60 struct xattr_list_element *element = malloc(sizeof(struct xattr_list_element));
61 element->inode = inode;
62 element->header = header;
63 element->next = aux_info.xattrs;
64 aux_info.xattrs = element;
65}
66
Colin Crossec0a2e82010-06-11 14:21:37 -070067static void region_list_remove(struct region_list *list, struct region *reg)
68{
69 if (reg->prev)
70 reg->prev->next = reg->next;
71
72 if (reg->next)
73 reg->next->prev = reg->prev;
74
75 if (list->first == reg)
76 list->first = reg->next;
77
78 if (list->last == reg)
79 list->last = reg->prev;
80
81 reg->next = NULL;
82 reg->prev = NULL;
83}
84
Mohamad Ayyash95791982016-02-20 03:46:00 +000085void region_list_append(struct region_list *list, struct region *reg)
Colin Crossec0a2e82010-06-11 14:21:37 -070086{
87 if (list->first == NULL) {
88 list->first = reg;
89 list->last = reg;
90 list->iter = reg;
91 list->partial_iter = 0;
92 reg->prev = NULL;
93 } else {
94 list->last->next = reg;
95 reg->prev = list->last;
96 list->last = reg;
97 }
98 reg->next = NULL;
99}
100
Mohamad Ayyashf7124d62016-04-29 11:14:02 -0700101void region_list_merge(struct region_list *list1, struct region_list *list2)
102{
103 if (list1->first == NULL) {
104 list1->first = list2->first;
105 list1->last = list2->last;
106 list1->iter = list2->first;
107 list1->partial_iter = 0;
108 list1->first->prev = NULL;
109 } else {
110 list1->last->next = list2->first;
111 list2->first->prev = list1->last;
112 list1->last = list2->last;
113 }
114}
Colin Crossec0a2e82010-06-11 14:21:37 -0700115#if 0
116static void dump_starting_from(struct region *reg)
117{
118 for (; reg; reg = reg->next) {
119 printf("%p: Blocks %d-%d (%d)\n", reg,
Doug Zongkerbec598e2014-08-12 11:35:37 -0700120 reg->block, reg->block + reg->len - 1, reg->len)
Colin Crossec0a2e82010-06-11 14:21:37 -0700121 }
122}
123
124static void dump_region_lists(struct block_allocation *alloc) {
125
126 printf("Main list:\n");
127 dump_starting_from(alloc->list.first);
128
129 printf("OOB list:\n");
130 dump_starting_from(alloc->oob_list.first);
131}
132#endif
133
Mohamad Ayyash95791982016-02-20 03:46:00 +0000134void print_blocks(FILE* f, struct block_allocation *alloc, char separator)
Doug Zongkerbec598e2014-08-12 11:35:37 -0700135{
136 struct region *reg;
Mohamad Ayyash95791982016-02-20 03:46:00 +0000137 fputc(' ', f);
Doug Zongkerbec598e2014-08-12 11:35:37 -0700138 for (reg = alloc->list.first; reg; reg = reg->next) {
139 if (reg->len == 1) {
Mohamad Ayyash95791982016-02-20 03:46:00 +0000140 fprintf(f, "%d", reg->block);
Doug Zongkerbec598e2014-08-12 11:35:37 -0700141 } else {
Mohamad Ayyash95791982016-02-20 03:46:00 +0000142 fprintf(f, "%d-%d", reg->block, reg->block + reg->len - 1);
Doug Zongkerbec598e2014-08-12 11:35:37 -0700143 }
Mohamad Ayyash95791982016-02-20 03:46:00 +0000144 fputc(separator, f);
Doug Zongkerbec598e2014-08-12 11:35:37 -0700145 }
146 fputc('\n', f);
147}
148
Colin Crossec0a2e82010-06-11 14:21:37 -0700149void append_region(struct block_allocation *alloc,
150 u32 block, u32 len, int bg_num)
151{
Colin Cross8aef66d2010-06-20 23:22:12 -0700152 struct region *reg;
153 reg = malloc(sizeof(struct region));
154 reg->block = block;
155 reg->len = len;
156 reg->bg = bg_num;
157 reg->next = NULL;
Colin Crossec0a2e82010-06-11 14:21:37 -0700158
Colin Cross8aef66d2010-06-20 23:22:12 -0700159 region_list_append(&alloc->list, reg);
Colin Crossec0a2e82010-06-11 14:21:37 -0700160}
161
162static void allocate_bg_inode_table(struct block_group_info *bg)
163{
164 if (bg->inode_table != NULL)
165 return;
166
167 u32 block = bg->first_block + 2;
168
169 if (bg->has_superblock)
Colin Cross22742ce2010-12-22 16:01:52 -0800170 block += aux_info.bg_desc_blocks + info.bg_desc_reserve_blocks + 1;
Colin Crossec0a2e82010-06-11 14:21:37 -0700171
172 bg->inode_table = calloc(aux_info.inode_table_blocks, info.block_size);
173 if (bg->inode_table == NULL)
174 critical_error_errno("calloc");
175
Colin Cross782879a2014-01-23 13:08:16 -0800176 sparse_file_add_data(ext4_sparse_file, bg->inode_table,
Colin Crossf0ee37f2012-04-24 17:48:43 -0700177 aux_info.inode_table_blocks * info.block_size, block);
Colin Crossec0a2e82010-06-11 14:21:37 -0700178
Colin Cross56497f22013-02-04 00:44:55 -0800179 bg->flags &= ~EXT4_BG_INODE_UNINIT;
Ken Sumrall107a9f12011-06-29 20:28:30 -0700180}
181
Colin Crossec0a2e82010-06-11 14:21:37 -0700182static int bitmap_set_bit(u8 *bitmap, u32 bit)
183{
184 if (bitmap[bit / 8] & 1 << (bit % 8))
185 return 1;
186
187 bitmap[bit / 8] |= 1 << (bit % 8);
188 return 0;
189}
190
191static int bitmap_set_8_bits(u8 *bitmap, u32 bit)
192{
193 int ret = bitmap[bit / 8];
194 bitmap[bit / 8] = 0xFF;
195 return ret;
196}
197
198/* Marks a the first num_blocks blocks in a block group as used, and accounts
199 for them in the block group free block info. */
Mohamad Ayyasha6866eb2016-03-02 21:10:45 -0800200static int reserve_blocks(struct block_group_info *bg, u32 bg_num, u32 start, u32 num)
Colin Crossec0a2e82010-06-11 14:21:37 -0700201{
202 unsigned int i = 0;
203
204 u32 block = start;
Colin Crossec0a2e82010-06-11 14:21:37 -0700205 for (i = 0; i < num && block % 8 != 0; i++, block++) {
206 if (bitmap_set_bit(bg->block_bitmap, block)) {
Mohamad Ayyasha6866eb2016-03-02 21:10:45 -0800207 error("attempted to reserve already reserved block %d in block group %d", block, bg_num);
Colin Crossec0a2e82010-06-11 14:21:37 -0700208 return -1;
209 }
210 }
211
212 for (; i + 8 <= (num & ~7); i += 8, block += 8) {
213 if (bitmap_set_8_bits(bg->block_bitmap, block)) {
Mohamad Ayyasha6866eb2016-03-02 21:10:45 -0800214 error("attempted to reserve already reserved block %d in block group %d", block, bg_num);
Colin Crossec0a2e82010-06-11 14:21:37 -0700215 return -1;
216 }
217 }
218
219 for (; i < num; i++, block++) {
220 if (bitmap_set_bit(bg->block_bitmap, block)) {
Mohamad Ayyasha6866eb2016-03-02 21:10:45 -0800221 error("attempted to reserve already reserved block %d in block group %d", block, bg_num);
Colin Crossec0a2e82010-06-11 14:21:37 -0700222 return -1;
223 }
224 }
225
226 bg->free_blocks -= num;
Colin Crossec0a2e82010-06-11 14:21:37 -0700227
228 return 0;
229}
230
Mohamad Ayyash95791982016-02-20 03:46:00 +0000231static void free_blocks(struct block_group_info *bg, u32 block, u32 num_blocks)
Colin Crossec0a2e82010-06-11 14:21:37 -0700232{
233 unsigned int i;
Colin Crossec0a2e82010-06-11 14:21:37 -0700234 for (i = 0; i < num_blocks; i++, block--)
235 bg->block_bitmap[block / 8] &= ~(1 << (block % 8));
236 bg->free_blocks += num_blocks;
Mohamad Ayyashbe25a222016-09-07 11:07:55 -0700237 for (i = bg->chunk_count; i > 0 ;) {
238 --i;
Mohamad Ayyash62b5fa42016-09-01 15:05:48 -0700239 if (bg->chunks[i].len >= num_blocks && bg->chunks[i].block <= block) {
240 if (bg->chunks[i].block == block) {
241 bg->chunks[i].block += num_blocks;
242 bg->chunks[i].len -= num_blocks;
243 } else if (bg->chunks[i].block + bg->chunks[i].len - 1 == block + num_blocks) {
244 bg->chunks[i].len -= num_blocks;
245 }
246 break;
247 }
248 }
Colin Crossec0a2e82010-06-11 14:21:37 -0700249}
250
251/* Reduces an existing allocation by len blocks by return the last blocks
252 to the free pool in their block group. Assumes that the blocks being
253 returned were the last ones allocated out of the block group */
254void reduce_allocation(struct block_allocation *alloc, u32 len)
255{
256 while (len) {
257 struct region *last_reg = alloc->list.last;
Mohamad Ayyash95791982016-02-20 03:46:00 +0000258 struct block_group_info *bg = &aux_info.bgs[last_reg->bg];
Colin Crossec0a2e82010-06-11 14:21:37 -0700259
260 if (last_reg->len > len) {
Mohamad Ayyash95791982016-02-20 03:46:00 +0000261 free_blocks(bg, last_reg->block + last_reg->len - bg->first_block - 1, len);
Colin Crossec0a2e82010-06-11 14:21:37 -0700262 last_reg->len -= len;
263 len = 0;
264 } else {
Colin Crossa1a175a2010-06-17 17:27:20 -0700265 struct region *reg = alloc->list.last->prev;
Mohamad Ayyash95791982016-02-20 03:46:00 +0000266 free_blocks(bg, last_reg->block + last_reg->len - bg->first_block - 1, last_reg->len);
Colin Crossec0a2e82010-06-11 14:21:37 -0700267 len -= last_reg->len;
Colin Crossa1a175a2010-06-17 17:27:20 -0700268 if (reg) {
Colin Crossec0a2e82010-06-11 14:21:37 -0700269 reg->next = NULL;
Colin Crossa1a175a2010-06-17 17:27:20 -0700270 } else {
271 alloc->list.first = NULL;
272 alloc->list.last = NULL;
273 alloc->list.iter = NULL;
274 alloc->list.partial_iter = 0;
275 }
Colin Crossec0a2e82010-06-11 14:21:37 -0700276 free(last_reg);
277 }
278 }
279}
280
281static void init_bg(struct block_group_info *bg, unsigned int i)
282{
283 int header_blocks = 2 + aux_info.inode_table_blocks;
284
285 bg->has_superblock = ext4_bg_has_super_block(i);
286
287 if (bg->has_superblock)
Colin Cross22742ce2010-12-22 16:01:52 -0800288 header_blocks += 1 + aux_info.bg_desc_blocks + info.bg_desc_reserve_blocks;
Colin Crossec0a2e82010-06-11 14:21:37 -0700289
290 bg->bitmaps = calloc(info.block_size, 2);
291 bg->block_bitmap = bg->bitmaps;
292 bg->inode_bitmap = bg->bitmaps + info.block_size;
293
294 bg->header_blocks = header_blocks;
295 bg->first_block = aux_info.first_data_block + i * info.blocks_per_group;
296
297 u32 block = bg->first_block;
298 if (bg->has_superblock)
Colin Cross22742ce2010-12-22 16:01:52 -0800299 block += 1 + aux_info.bg_desc_blocks + info.bg_desc_reserve_blocks;
Colin Cross782879a2014-01-23 13:08:16 -0800300 sparse_file_add_data(ext4_sparse_file, bg->bitmaps, 2 * info.block_size,
Colin Crossf0ee37f2012-04-24 17:48:43 -0700301 block);
Colin Crossec0a2e82010-06-11 14:21:37 -0700302
303 bg->data_blocks_used = 0;
304 bg->free_blocks = info.blocks_per_group;
Colin Crossec0a2e82010-06-11 14:21:37 -0700305 bg->free_inodes = info.inodes_per_group;
306 bg->first_free_inode = 1;
Mohamad Ayyashdedf8f92016-04-14 19:43:31 -0700307 bg->flags = EXT4_BG_INODE_UNINIT;
Colin Crossec0a2e82010-06-11 14:21:37 -0700308
Mohamad Ayyash95791982016-02-20 03:46:00 +0000309 bg->chunk_count = 0;
310 bg->max_chunk_count = 1;
311 bg->chunks = (struct region*) calloc(bg->max_chunk_count, sizeof(struct region));
312
Mohamad Ayyasha6866eb2016-03-02 21:10:45 -0800313 if (reserve_blocks(bg, i, 0, bg->header_blocks) < 0)
Colin Crossec0a2e82010-06-11 14:21:37 -0700314 error("failed to reserve %u blocks in block group %u\n", bg->header_blocks, i);
Mohamad Ayyash95791982016-02-20 03:46:00 +0000315 // Add empty starting delimiter chunk
316 reserve_bg_chunk(i, bg->header_blocks, 0);
Colin Crossec0a2e82010-06-11 14:21:37 -0700317
Ken Sumrall17de6542013-08-15 19:06:29 -0700318 if (bg->first_block + info.blocks_per_group > aux_info.len_blocks) {
319 u32 overrun = bg->first_block + info.blocks_per_group - aux_info.len_blocks;
Mohamad Ayyasha6866eb2016-03-02 21:10:45 -0800320 reserve_blocks(bg, i, info.blocks_per_group - overrun, overrun);
Mohamad Ayyash95791982016-02-20 03:46:00 +0000321 // Add empty ending delimiter chunk
322 reserve_bg_chunk(i, info.blocks_per_group - overrun, 0);
323 } else {
324 reserve_bg_chunk(i, info.blocks_per_group - 1, 0);
Ken Sumrall17de6542013-08-15 19:06:29 -0700325 }
Mohamad Ayyash95791982016-02-20 03:46:00 +0000326
Colin Crossec0a2e82010-06-11 14:21:37 -0700327}
328
329void block_allocator_init()
330{
331 unsigned int i;
332
333 aux_info.bgs = calloc(sizeof(struct block_group_info), aux_info.groups);
334 if (aux_info.bgs == NULL)
335 critical_error_errno("calloc");
336
337 for (i = 0; i < aux_info.groups; i++)
338 init_bg(&aux_info.bgs[i], i);
339}
340
341void block_allocator_free()
342{
343 unsigned int i;
344
345 for (i = 0; i < aux_info.groups; i++) {
346 free(aux_info.bgs[i].bitmaps);
347 free(aux_info.bgs[i].inode_table);
348 }
349 free(aux_info.bgs);
350}
351
Colin Crossec0a2e82010-06-11 14:21:37 -0700352/* Allocate a single block and return its block number */
353u32 allocate_block()
354{
Mohamad Ayyash95791982016-02-20 03:46:00 +0000355 u32 block;
356 struct block_allocation *blk_alloc = allocate_blocks(1);
357 if (!blk_alloc) {
358 return EXT4_ALLOCATE_FAILED;
Colin Crossec0a2e82010-06-11 14:21:37 -0700359 }
Mohamad Ayyash95791982016-02-20 03:46:00 +0000360 block = blk_alloc->list.first->block;
361 free_alloc(blk_alloc);
362 return block;
Colin Crossec0a2e82010-06-11 14:21:37 -0700363}
364
Colin Crosseb3915a2014-01-21 00:04:04 -0800365static struct region *ext4_allocate_best_fit_partial(u32 len)
Colin Crossec0a2e82010-06-11 14:21:37 -0700366{
Dmitry Shmidtcd205302016-11-18 15:38:47 -0800367 unsigned int i;
368 int j;
Mohamad Ayyash95791982016-02-20 03:46:00 +0000369 unsigned int found_bg = 0, found_prev_chunk = 0, found_block = 0;
370 u32 found_allocate_len = 0;
371 bool minimize = false;
372 struct block_group_info *bgs = aux_info.bgs;
373 struct region *reg;
Mohamad Ayyash18785a82016-02-19 21:16:34 +0000374
Colin Crossec0a2e82010-06-11 14:21:37 -0700375 for (i = 0; i < aux_info.groups; i++) {
Mohamad Ayyash95791982016-02-20 03:46:00 +0000376 for (j = 1; j < bgs[i].chunk_count; j++) {
377 u32 hole_start, hole_size;
378 hole_start = bgs[i].chunks[j-1].block + bgs[i].chunks[j-1].len;
379 hole_size = bgs[i].chunks[j].block - hole_start;
380 if (hole_size == len) {
381 // Perfect fit i.e. right between 2 chunks no need to keep searching
382 found_bg = i;
383 found_prev_chunk = j - 1;
384 found_block = hole_start;
385 found_allocate_len = hole_size;
386 goto done;
387 } else if (hole_size > len && (found_allocate_len == 0 || (found_allocate_len > hole_size))) {
388 found_bg = i;
389 found_prev_chunk = j - 1;
390 found_block = hole_start;
391 found_allocate_len = hole_size;
392 minimize = true;
393 } else if (!minimize) {
394 if (found_allocate_len < hole_size) {
395 found_bg = i;
396 found_prev_chunk = j - 1;
397 found_block = hole_start;
398 found_allocate_len = hole_size;
399 }
400 }
Colin Crossec0a2e82010-06-11 14:21:37 -0700401 }
402 }
Colin Crosseb3915a2014-01-21 00:04:04 -0800403
Mohamad Ayyash95791982016-02-20 03:46:00 +0000404 if (found_allocate_len == 0) {
Colin Crosseb3915a2014-01-21 00:04:04 -0800405 error("failed to allocate %u blocks, out of space?", len);
Mohamad Ayyash95791982016-02-20 03:46:00 +0000406 return NULL;
Colin Crosseb3915a2014-01-21 00:04:04 -0800407 }
Mohamad Ayyash95791982016-02-20 03:46:00 +0000408 if (found_allocate_len > len) found_allocate_len = len;
409done:
410 // reclaim allocated space in chunk
411 bgs[found_bg].chunks[found_prev_chunk].len += found_allocate_len;
412 if (reserve_blocks(&bgs[found_bg],
Mohamad Ayyasha6866eb2016-03-02 21:10:45 -0800413 found_bg,
Mohamad Ayyash95791982016-02-20 03:46:00 +0000414 found_block,
415 found_allocate_len) < 0) {
416 error("failed to reserve %u blocks in block group %u\n", found_allocate_len, found_bg);
417 return NULL;
418 }
419 bgs[found_bg].data_blocks_used += found_allocate_len;
420 reg = malloc(sizeof(struct region));
421 reg->block = found_block + bgs[found_bg].first_block;
422 reg->len = found_allocate_len;
423 reg->next = NULL;
424 reg->prev = NULL;
425 reg->bg = found_bg;
426 return reg;
Colin Crossec0a2e82010-06-11 14:21:37 -0700427}
428
Colin Crosseb3915a2014-01-21 00:04:04 -0800429static struct region *ext4_allocate_best_fit(u32 len)
Colin Crossec0a2e82010-06-11 14:21:37 -0700430{
431 struct region *first_reg = NULL;
432 struct region *prev_reg = NULL;
433 struct region *reg;
434
435 while (len > 0) {
Colin Crosseb3915a2014-01-21 00:04:04 -0800436 reg = ext4_allocate_best_fit_partial(len);
Colin Crossec0a2e82010-06-11 14:21:37 -0700437 if (reg == NULL)
438 return NULL;
439
440 if (first_reg == NULL)
441 first_reg = reg;
442
443 if (prev_reg) {
444 prev_reg->next = reg;
445 reg->prev = prev_reg;
446 }
447
448 prev_reg = reg;
449 len -= reg->len;
450 }
451
452 return first_reg;
453}
454
Colin Crossec0a2e82010-06-11 14:21:37 -0700455/* Allocate len blocks. The blocks may be spread across multiple block groups,
456 and are returned in a linked list of the blocks in each block group. The
457 allocation algorithm is:
Mohamad Ayyash95791982016-02-20 03:46:00 +0000458 1. If the remaining allocation is larger than any available contiguous region,
459 allocate the largest contiguous region and loop
460 2. Otherwise, allocate the smallest contiguous region that it fits in
Colin Crossec0a2e82010-06-11 14:21:37 -0700461*/
462struct block_allocation *allocate_blocks(u32 len)
463{
Colin Crosseb3915a2014-01-21 00:04:04 -0800464 struct region *reg = ext4_allocate_best_fit(len);
Colin Crossec0a2e82010-06-11 14:21:37 -0700465
466 if (reg == NULL)
467 return NULL;
468
469 struct block_allocation *alloc = create_allocation();
470 alloc->list.first = reg;
Mohamad Ayyash95791982016-02-20 03:46:00 +0000471 while (reg->next != NULL)
472 reg = reg->next;
Colin Cross8aef66d2010-06-20 23:22:12 -0700473 alloc->list.last = reg;
Colin Crossec0a2e82010-06-11 14:21:37 -0700474 alloc->list.iter = alloc->list.first;
475 alloc->list.partial_iter = 0;
476 return alloc;
477}
478
479/* Returns the number of discontiguous regions used by an allocation */
480int block_allocation_num_regions(struct block_allocation *alloc)
481{
482 unsigned int i;
483 struct region *reg = alloc->list.first;
484
485 for (i = 0; reg != NULL; reg = reg->next)
486 i++;
487
488 return i;
489}
490
491int block_allocation_len(struct block_allocation *alloc)
492{
493 unsigned int i;
Colin Cross8aef66d2010-06-20 23:22:12 -0700494 struct region *reg = alloc->list.first;
Colin Crossec0a2e82010-06-11 14:21:37 -0700495
496 for (i = 0; reg != NULL; reg = reg->next)
497 i += reg->len;
498
499 return i;
500}
501
502/* Returns the block number of the block'th block in an allocation */
503u32 get_block(struct block_allocation *alloc, u32 block)
504{
Colin Cross8aef66d2010-06-20 23:22:12 -0700505 struct region *reg = alloc->list.iter;
506 block += alloc->list.partial_iter;
Colin Crossec0a2e82010-06-11 14:21:37 -0700507
Colin Cross8aef66d2010-06-20 23:22:12 -0700508 for (; reg; reg = reg->next) {
Colin Crossec0a2e82010-06-11 14:21:37 -0700509 if (block < reg->len)
510 return reg->block + block;
511 block -= reg->len;
512 }
513 return EXT4_ALLOCATE_FAILED;
514}
515
516u32 get_oob_block(struct block_allocation *alloc, u32 block)
517{
Colin Cross8aef66d2010-06-20 23:22:12 -0700518 struct region *reg = alloc->oob_list.iter;
519 block += alloc->oob_list.partial_iter;
Colin Crossec0a2e82010-06-11 14:21:37 -0700520
Colin Cross8aef66d2010-06-20 23:22:12 -0700521 for (; reg; reg = reg->next) {
Colin Crossec0a2e82010-06-11 14:21:37 -0700522 if (block < reg->len)
523 return reg->block + block;
524 block -= reg->len;
525 }
526 return EXT4_ALLOCATE_FAILED;
527}
528
529/* Gets the starting block and length in blocks of the first region
530 of an allocation */
531void get_region(struct block_allocation *alloc, u32 *block, u32 *len)
532{
533 *block = alloc->list.iter->block;
534 *len = alloc->list.iter->len - alloc->list.partial_iter;
535}
536
537/* Move to the next region in an allocation */
538void get_next_region(struct block_allocation *alloc)
539{
540 alloc->list.iter = alloc->list.iter->next;
541 alloc->list.partial_iter = 0;
542}
543
544/* Returns the number of free blocks in a block group */
545u32 get_free_blocks(u32 bg)
546{
547 return aux_info.bgs[bg].free_blocks;
548}
549
550int last_region(struct block_allocation *alloc)
551{
552 return (alloc->list.iter == NULL);
553}
554
555void rewind_alloc(struct block_allocation *alloc)
556{
557 alloc->list.iter = alloc->list.first;
558 alloc->list.partial_iter = 0;
559}
560
561static struct region *do_split_allocation(struct block_allocation *alloc, u32 len)
562{
Colin Cross8aef66d2010-06-20 23:22:12 -0700563 struct region *reg = alloc->list.iter;
564 struct region *new;
565 struct region *tmp;
Colin Crossec0a2e82010-06-11 14:21:37 -0700566
Colin Cross8aef66d2010-06-20 23:22:12 -0700567 while (reg && len >= reg->len) {
Colin Crossec0a2e82010-06-11 14:21:37 -0700568 len -= reg->len;
569 reg = reg->next;
570 }
571
572 if (reg == NULL && len > 0)
573 return NULL;
574
575 if (len > 0) {
576 new = malloc(sizeof(struct region));
577
578 new->bg = reg->bg;
579 new->block = reg->block + len;
580 new->len = reg->len - len;
581 new->next = reg->next;
582 new->prev = reg;
583
584 reg->next = new;
585 reg->len = len;
586
587 tmp = alloc->list.iter;
Colin Cross8aef66d2010-06-20 23:22:12 -0700588 alloc->list.iter = new;
Colin Crossec0a2e82010-06-11 14:21:37 -0700589 return tmp;
590 } else {
591 return reg;
592 }
593}
594
595/* Splits an allocation into two allocations. The returned allocation will
596 point to the first half, and the original allocation ptr will point to the
597 second half. */
598static struct region *split_allocation(struct block_allocation *alloc, u32 len)
599{
600 /* First make sure there is a split at the current ptr */
601 do_split_allocation(alloc, alloc->list.partial_iter);
602
603 /* Then split off len blocks */
604 struct region *middle = do_split_allocation(alloc, len);
605 alloc->list.partial_iter = 0;
606 return middle;
607}
608
609/* Reserve the next blocks for oob data (indirect or extent blocks) */
610int reserve_oob_blocks(struct block_allocation *alloc, int blocks)
611{
612 struct region *oob = split_allocation(alloc, blocks);
Colin Cross8aef66d2010-06-20 23:22:12 -0700613 struct region *next;
Colin Crossec0a2e82010-06-11 14:21:37 -0700614
615 if (oob == NULL)
616 return -1;
617
618 while (oob && oob != alloc->list.iter) {
619 next = oob->next;
620 region_list_remove(&alloc->list, oob);
621 region_list_append(&alloc->oob_list, oob);
622 oob = next;
623 }
624
625 return 0;
626}
627
628static int advance_list_ptr(struct region_list *list, int blocks)
629{
630 struct region *reg = list->iter;
631
632 while (reg != NULL && blocks > 0) {
633 if (reg->len > list->partial_iter + blocks) {
634 list->partial_iter += blocks;
635 return 0;
636 }
637
638 blocks -= (reg->len - list->partial_iter);
639 list->partial_iter = 0;
640 reg = reg->next;
641 }
642
643 if (blocks > 0)
644 return -1;
645
646 return 0;
647}
648
649/* Move the allocation pointer forward */
650int advance_blocks(struct block_allocation *alloc, int blocks)
651{
652 return advance_list_ptr(&alloc->list, blocks);
653}
654
655int advance_oob_blocks(struct block_allocation *alloc, int blocks)
656{
657 return advance_list_ptr(&alloc->oob_list, blocks);
658}
659
660int append_oob_allocation(struct block_allocation *alloc, u32 len)
661{
Colin Crosseb3915a2014-01-21 00:04:04 -0800662 struct region *reg = ext4_allocate_best_fit(len);
Colin Crossec0a2e82010-06-11 14:21:37 -0700663
664 if (reg == NULL) {
665 error("failed to allocate %d blocks", len);
666 return -1;
667 }
668
669 for (; reg; reg = reg->next)
670 region_list_append(&alloc->oob_list, reg);
671
672 return 0;
673}
674
675/* Returns an ext4_inode structure for an inode number */
676struct ext4_inode *get_inode(u32 inode)
677{
678 inode -= 1;
679 int bg = inode / info.inodes_per_group;
680 inode %= info.inodes_per_group;
681
682 allocate_bg_inode_table(&aux_info.bgs[bg]);
Colin Cross8aef66d2010-06-20 23:22:12 -0700683 return (struct ext4_inode *)(aux_info.bgs[bg].inode_table + inode *
684 info.inode_size);
Colin Crossec0a2e82010-06-11 14:21:37 -0700685}
686
Nick Kralevich4df62f32013-02-07 14:21:34 -0800687struct ext4_xattr_header *get_xattr_block_for_inode(struct ext4_inode *inode)
688{
689 struct ext4_xattr_header *block = xattr_list_find(inode);
690 if (block != NULL)
691 return block;
692
693 u32 block_num = allocate_block();
694 block = calloc(info.block_size, 1);
695 if (block == NULL) {
696 error("get_xattr: failed to allocate %d", info.block_size);
697 return NULL;
698 }
699
700 block->h_magic = cpu_to_le32(EXT4_XATTR_MAGIC);
701 block->h_refcount = cpu_to_le32(1);
702 block->h_blocks = cpu_to_le32(1);
703 inode->i_blocks_lo = cpu_to_le32(le32_to_cpu(inode->i_blocks_lo) + (info.block_size / 512));
704 inode->i_file_acl_lo = cpu_to_le32(block_num);
705
Colin Cross782879a2014-01-23 13:08:16 -0800706 int result = sparse_file_add_data(ext4_sparse_file, block, info.block_size, block_num);
Nick Kralevich4df62f32013-02-07 14:21:34 -0800707 if (result != 0) {
708 error("get_xattr: sparse_file_add_data failure %d", result);
709 free(block);
710 return NULL;
711 }
712 xattr_list_insert(inode, block);
713 return block;
714}
715
Colin Crossec0a2e82010-06-11 14:21:37 -0700716/* Mark the first len inodes in a block group as used */
717u32 reserve_inodes(int bg, u32 num)
718{
719 unsigned int i;
720 u32 inode;
721
722 if (get_free_inodes(bg) < num)
723 return EXT4_ALLOCATE_FAILED;
724
725 for (i = 0; i < num; i++) {
726 inode = aux_info.bgs[bg].first_free_inode + i - 1;
727 aux_info.bgs[bg].inode_bitmap[inode / 8] |= 1 << (inode % 8);
728 }
729
730 inode = aux_info.bgs[bg].first_free_inode;
731
732 aux_info.bgs[bg].first_free_inode += num;
733 aux_info.bgs[bg].free_inodes -= num;
734
735 return inode;
736}
737
738/* Returns the first free inode number
739 TODO: Inodes should be allocated in the block group of the data? */
740u32 allocate_inode()
741{
742 unsigned int bg;
743 u32 inode;
744
745 for (bg = 0; bg < aux_info.groups; bg++) {
746 inode = reserve_inodes(bg, 1);
747 if (inode != EXT4_ALLOCATE_FAILED)
748 return bg * info.inodes_per_group + inode;
749 }
750
751 return EXT4_ALLOCATE_FAILED;
752}
753
754/* Returns the number of free inodes in a block group */
755u32 get_free_inodes(u32 bg)
756{
757 return aux_info.bgs[bg].free_inodes;
758}
759
760/* Increments the directory count of the block group that contains inode */
761void add_directory(u32 inode)
762{
763 int bg = (inode - 1) / info.inodes_per_group;
764 aux_info.bgs[bg].used_dirs += 1;
765}
766
767/* Returns the number of inodes in a block group that are directories */
768u16 get_directories(int bg)
769{
770 return aux_info.bgs[bg].used_dirs;
771}
772
Colin Cross56497f22013-02-04 00:44:55 -0800773/* Returns the flags for a block group */
774u16 get_bg_flags(int bg)
775{
776 return aux_info.bgs[bg].flags;
777}
778
Colin Crossec0a2e82010-06-11 14:21:37 -0700779/* Frees the memory used by a linked list of allocation regions */
780void free_alloc(struct block_allocation *alloc)
781{
782 struct region *reg;
783
784 reg = alloc->list.first;
785 while (reg) {
786 struct region *next = reg->next;
787 free(reg);
788 reg = next;
789 }
790
791 reg = alloc->oob_list.first;
792 while (reg) {
793 struct region *next = reg->next;
794 free(reg);
795 reg = next;
796 }
797
798 free(alloc);
799}
Mohamad Ayyash95791982016-02-20 03:46:00 +0000800
801void reserve_bg_chunk(int bg, u32 start_block, u32 size) {
802 struct block_group_info *bgs = aux_info.bgs;
803 int chunk_count;
804 if (bgs[bg].chunk_count == bgs[bg].max_chunk_count) {
805 bgs[bg].max_chunk_count *= 2;
806 bgs[bg].chunks = realloc(bgs[bg].chunks, bgs[bg].max_chunk_count * sizeof(struct region));
807 if (!bgs[bg].chunks)
808 critical_error("realloc failed");
809 }
810 chunk_count = bgs[bg].chunk_count;
811 bgs[bg].chunks[chunk_count].block = start_block;
812 bgs[bg].chunks[chunk_count].len = size;
813 bgs[bg].chunks[chunk_count].bg = bg;
814 bgs[bg].chunk_count++;
815}
816
817int reserve_blocks_for_allocation(struct block_allocation *alloc) {
818 struct region *reg;
819 struct block_group_info *bgs = aux_info.bgs;
820
821 if (!alloc) return 0;
822 reg = alloc->list.first;
823 while (reg != NULL) {
Mohamad Ayyasha6866eb2016-03-02 21:10:45 -0800824 if (reserve_blocks(&bgs[reg->bg], reg->bg, reg->block - bgs[reg->bg].first_block, reg->len) < 0) {
Mohamad Ayyash95791982016-02-20 03:46:00 +0000825 return -1;
Mohamad Ayyasha6866eb2016-03-02 21:10:45 -0800826 }
Mohamad Ayyash95791982016-02-20 03:46:00 +0000827 reg = reg->next;
828 }
829 return 0;
830}
831