Whamcloud - gitweb
AOSP: e2fsdroid/libext2fs: move hashmap into libext2fs
[tools/e2fsprogs.git] / contrib / android / basefs_allocator.c
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         /* Override 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 }