Home | History | Annotate | Download | only in android
      1 #include <sys/types.h>
      2 #include <sys/stat.h>
      3 #include "basefs_allocator.h"
      4 #include "block_range.h"
      5 #include "hashmap.h"
      6 #include "base_fs.h"
      7 
      8 struct base_fs_allocator {
      9 	struct ext2fs_hashmap *entries;
     10 	struct basefs_entry *cur_entry;
     11 };
     12 
     13 static errcode_t basefs_block_allocator(ext2_filsys, blk64_t, blk64_t *,
     14 					struct blk_alloc_ctx *ctx);
     15 
     16 static void fs_free_blocks_range(ext2_filsys fs, struct block_range *blocks)
     17 {
     18 	while (blocks) {
     19 		ext2fs_unmark_block_bitmap_range2(fs->block_map, blocks->start,
     20 			blocks->end - blocks->start + 1);
     21 		blocks = blocks->next;
     22 	}
     23 }
     24 
     25 static void fs_reserve_blocks_range(ext2_filsys fs, struct block_range *blocks)
     26 {
     27 	while (blocks) {
     28 		ext2fs_mark_block_bitmap_range2(fs->block_map,
     29 			blocks->start, blocks->end - blocks->start + 1);
     30 		blocks = blocks->next;
     31 	}
     32 }
     33 
     34 errcode_t base_fs_alloc_load(ext2_filsys fs, const char *file,
     35 			     const char *mountpoint)
     36 {
     37 	errcode_t retval;
     38 	struct basefs_entry *e;
     39 	struct ext2fs_hashmap_entry *it = NULL;
     40 	struct base_fs_allocator *allocator;
     41 	struct ext2fs_hashmap *entries = basefs_parse(file, mountpoint);
     42 	if (!entries)
     43 		return -1;
     44 
     45 	allocator = malloc(sizeof(*allocator));
     46 	if (!allocator)
     47 		goto err_alloc;
     48 
     49 	retval = ext2fs_read_bitmaps(fs);
     50 	if (retval)
     51 		goto err_bitmap;
     52 	while ((e = ext2fs_hashmap_iter_in_order(entries, &it)))
     53 		fs_reserve_blocks_range(fs, e->head);
     54 
     55 	allocator->cur_entry = NULL;
     56 	allocator->entries = entries;
     57 
     58 	/* Overhide the default allocator */
     59 	fs->get_alloc_block2 = basefs_block_allocator;
     60 	fs->priv_data = allocator;
     61 
     62 	return 0;
     63 
     64 err_bitmap:
     65 	free(allocator);
     66 err_alloc:
     67 	ext2fs_hashmap_free(entries);
     68 	return EXIT_FAILURE;
     69 }
     70 
     71 static errcode_t basefs_block_allocator(ext2_filsys fs, blk64_t goal,
     72 					blk64_t *ret, struct blk_alloc_ctx *ctx)
     73 {
     74 	errcode_t retval;
     75 	struct block_range *next_range;
     76 	struct base_fs_allocator *allocator = fs->priv_data;
     77 	struct basefs_entry *e = allocator->cur_entry;
     78 
     79 	/* Try to get a block from the base_fs */
     80 	if (e && e->head && ctx && (ctx->flags & BLOCK_ALLOC_DATA)) {
     81 		*ret = e->head->start;
     82 		e->head->start += 1;
     83 		if (e->head->start > e->head->end) {
     84 			next_range = e->head->next;
     85 			free(e->head);
     86 			e->head = next_range;
     87 		}
     88 	} else { /* Allocate a new block */
     89 		retval = ext2fs_new_block2(fs, goal, fs->block_map, ret);
     90 		if (retval)
     91 			return retval;
     92 		ext2fs_mark_block_bitmap2(fs->block_map, *ret);
     93 	}
     94 	return 0;
     95 }
     96 
     97 void base_fs_alloc_cleanup(ext2_filsys fs)
     98 {
     99 	struct basefs_entry *e;
    100 	struct ext2fs_hashmap_entry *it = NULL;
    101 	struct base_fs_allocator *allocator = fs->priv_data;
    102 
    103 	while ((e = ext2fs_hashmap_iter_in_order(allocator->entries, &it))) {
    104 		fs_free_blocks_range(fs, e->head);
    105 		delete_block_ranges(e->head);
    106 		e->head = e->tail = NULL;
    107 	}
    108 
    109 	fs->priv_data = NULL;
    110 	fs->get_alloc_block2 = NULL;
    111 	ext2fs_hashmap_free(allocator->entries);
    112 	free(allocator);
    113 }
    114 
    115 errcode_t base_fs_alloc_set_target(ext2_filsys fs, const char *target_path,
    116 	const char *name EXT2FS_ATTR((unused)),
    117 	ext2_ino_t parent_ino EXT2FS_ATTR((unused)),
    118 	ext2_ino_t root EXT2FS_ATTR((unused)), mode_t mode)
    119 {
    120 	struct base_fs_allocator *allocator = fs->priv_data;
    121 
    122 	if (mode != S_IFREG)
    123 		return 0;
    124 
    125 	if (allocator)
    126 		allocator->cur_entry = ext2fs_hashmap_lookup(allocator->entries,
    127 						      target_path,
    128 						      strlen(target_path));
    129 	return 0;
    130 }
    131 
    132 errcode_t base_fs_alloc_unset_target(ext2_filsys fs,
    133         const char *target_path EXT2FS_ATTR((unused)),
    134 	const char *name EXT2FS_ATTR((unused)),
    135 	ext2_ino_t parent_ino EXT2FS_ATTR((unused)),
    136 	ext2_ino_t root EXT2FS_ATTR((unused)), mode_t mode)
    137 {
    138 	struct base_fs_allocator *allocator = fs->priv_data;
    139 
    140 	if (!allocator || !allocator->cur_entry || mode != S_IFREG)
    141 		return 0;
    142 
    143 	fs_free_blocks_range(fs, allocator->cur_entry->head);
    144 	delete_block_ranges(allocator->cur_entry->head);
    145 	allocator->cur_entry->head = allocator->cur_entry->tail = NULL;
    146 	allocator->cur_entry = NULL;
    147 	return 0;
    148 }
    149