• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
fs_free_blocks_range(ext2_filsys fs,struct block_range * blocks)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 
fs_reserve_blocks_range(ext2_filsys fs,struct block_range * blocks)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 
base_fs_alloc_load(ext2_filsys fs,const char * file,const char * mountpoint)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 
basefs_block_allocator(ext2_filsys fs,blk64_t goal,blk64_t * ret,struct blk_alloc_ctx * ctx)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 
base_fs_alloc_cleanup(ext2_filsys fs)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 
base_fs_alloc_set_target(ext2_filsys fs,const char * target_path,const char * name EXT2FS_ATTR ((unused)),ext2_ino_t parent_ino EXT2FS_ATTR ((unused)),ext2_ino_t root EXT2FS_ATTR ((unused)),mode_t mode)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 
base_fs_alloc_unset_target(ext2_filsys fs,const char * target_path EXT2FS_ATTR ((unused)),const char * name EXT2FS_ATTR ((unused)),ext2_ino_t parent_ino EXT2FS_ATTR ((unused)),ext2_ino_t root EXT2FS_ATTR ((unused)),mode_t mode)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