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 8struct base_fs_allocator { 9 struct ext2fs_hashmap *entries; 10 struct basefs_entry *cur_entry; 11}; 12 13static errcode_t basefs_block_allocator(ext2_filsys, blk64_t, blk64_t *, 14 struct blk_alloc_ctx *ctx); 15 16static 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 25static 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 34errcode_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 64err_bitmap: 65 free(allocator); 66err_alloc: 67 ext2fs_hashmap_free(entries); 68 return EXIT_FAILURE; 69} 70 71static 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 97void 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 115errcode_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 132errcode_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