1*6a54128fSAndroid Build Coastguard Worker #include <limits.h>
2*6a54128fSAndroid Build Coastguard Worker #include <sys/types.h>
3*6a54128fSAndroid Build Coastguard Worker #include <sys/stat.h>
4*6a54128fSAndroid Build Coastguard Worker #include "basefs_allocator.h"
5*6a54128fSAndroid Build Coastguard Worker #include "block_range.h"
6*6a54128fSAndroid Build Coastguard Worker #include "hashmap.h"
7*6a54128fSAndroid Build Coastguard Worker #include "base_fs.h"
8*6a54128fSAndroid Build Coastguard Worker
9*6a54128fSAndroid Build Coastguard Worker struct base_fs_allocator {
10*6a54128fSAndroid Build Coastguard Worker struct ext2fs_hashmap *entries;
11*6a54128fSAndroid Build Coastguard Worker struct basefs_entry *cur_entry;
12*6a54128fSAndroid Build Coastguard Worker /* The next expected logical block to allocate for cur_entry. */
13*6a54128fSAndroid Build Coastguard Worker blk64_t next_lblk;
14*6a54128fSAndroid Build Coastguard Worker /* Blocks which are definitely owned by a single inode in BaseFS. */
15*6a54128fSAndroid Build Coastguard Worker ext2fs_block_bitmap exclusive_block_map;
16*6a54128fSAndroid Build Coastguard Worker /* Blocks which are available to the first inode that requests it. */
17*6a54128fSAndroid Build Coastguard Worker ext2fs_block_bitmap dedup_block_map;
18*6a54128fSAndroid Build Coastguard Worker };
19*6a54128fSAndroid Build Coastguard Worker
20*6a54128fSAndroid Build Coastguard Worker static errcode_t basefs_block_allocator(ext2_filsys, blk64_t, blk64_t *,
21*6a54128fSAndroid Build Coastguard Worker struct blk_alloc_ctx *ctx);
22*6a54128fSAndroid Build Coastguard Worker
23*6a54128fSAndroid Build Coastguard Worker /*
24*6a54128fSAndroid Build Coastguard Worker * Free any reserved, but unconsumed block ranges in the allocator. This both
25*6a54128fSAndroid Build Coastguard Worker * frees the block_range_list data structure and unreserves exclusive blocks
26*6a54128fSAndroid Build Coastguard Worker * from the block map.
27*6a54128fSAndroid Build Coastguard Worker */
fs_free_blocks_range(ext2_filsys fs,struct base_fs_allocator * allocator,struct block_range_list * list)28*6a54128fSAndroid Build Coastguard Worker static void fs_free_blocks_range(ext2_filsys fs,
29*6a54128fSAndroid Build Coastguard Worker struct base_fs_allocator *allocator,
30*6a54128fSAndroid Build Coastguard Worker struct block_range_list *list)
31*6a54128fSAndroid Build Coastguard Worker {
32*6a54128fSAndroid Build Coastguard Worker ext2fs_block_bitmap exclusive_map = allocator->exclusive_block_map;
33*6a54128fSAndroid Build Coastguard Worker
34*6a54128fSAndroid Build Coastguard Worker blk64_t block;
35*6a54128fSAndroid Build Coastguard Worker while (list->head) {
36*6a54128fSAndroid Build Coastguard Worker block = consume_next_block(list);
37*6a54128fSAndroid Build Coastguard Worker if (ext2fs_test_block_bitmap2(exclusive_map, block)) {
38*6a54128fSAndroid Build Coastguard Worker ext2fs_unmark_block_bitmap2(fs->block_map, block);
39*6a54128fSAndroid Build Coastguard Worker ext2fs_unmark_block_bitmap2(exclusive_map, block);
40*6a54128fSAndroid Build Coastguard Worker }
41*6a54128fSAndroid Build Coastguard Worker }
42*6a54128fSAndroid Build Coastguard Worker }
43*6a54128fSAndroid Build Coastguard Worker
44*6a54128fSAndroid Build Coastguard Worker /*
45*6a54128fSAndroid Build Coastguard Worker * Free any blocks in the bitmap that were reserved but never used. This is
46*6a54128fSAndroid Build Coastguard Worker * needed to free dedup_block_map and ensure the free block bitmap is
47*6a54128fSAndroid Build Coastguard Worker * internally consistent.
48*6a54128fSAndroid Build Coastguard Worker */
fs_free_blocks_bitmap(ext2_filsys fs,ext2fs_block_bitmap bitmap)49*6a54128fSAndroid Build Coastguard Worker static void fs_free_blocks_bitmap(ext2_filsys fs, ext2fs_block_bitmap bitmap)
50*6a54128fSAndroid Build Coastguard Worker {
51*6a54128fSAndroid Build Coastguard Worker blk64_t block = 0;
52*6a54128fSAndroid Build Coastguard Worker blk64_t start = fs->super->s_first_data_block;
53*6a54128fSAndroid Build Coastguard Worker blk64_t end = ext2fs_blocks_count(fs->super) - 1;
54*6a54128fSAndroid Build Coastguard Worker errcode_t retval;
55*6a54128fSAndroid Build Coastguard Worker
56*6a54128fSAndroid Build Coastguard Worker for (;;) {
57*6a54128fSAndroid Build Coastguard Worker retval = ext2fs_find_first_set_block_bitmap2(bitmap, start, end,
58*6a54128fSAndroid Build Coastguard Worker &block);
59*6a54128fSAndroid Build Coastguard Worker if (retval)
60*6a54128fSAndroid Build Coastguard Worker break;
61*6a54128fSAndroid Build Coastguard Worker ext2fs_unmark_block_bitmap2(fs->block_map, block);
62*6a54128fSAndroid Build Coastguard Worker start = block + 1;
63*6a54128fSAndroid Build Coastguard Worker }
64*6a54128fSAndroid Build Coastguard Worker }
65*6a54128fSAndroid Build Coastguard Worker
basefs_allocator_free(ext2_filsys fs,struct base_fs_allocator * allocator)66*6a54128fSAndroid Build Coastguard Worker static void basefs_allocator_free(ext2_filsys fs,
67*6a54128fSAndroid Build Coastguard Worker struct base_fs_allocator *allocator)
68*6a54128fSAndroid Build Coastguard Worker {
69*6a54128fSAndroid Build Coastguard Worker struct basefs_entry *e;
70*6a54128fSAndroid Build Coastguard Worker struct ext2fs_hashmap_entry *it = NULL;
71*6a54128fSAndroid Build Coastguard Worker struct ext2fs_hashmap *entries = allocator->entries;
72*6a54128fSAndroid Build Coastguard Worker
73*6a54128fSAndroid Build Coastguard Worker if (entries) {
74*6a54128fSAndroid Build Coastguard Worker while ((e = ext2fs_hashmap_iter_in_order(entries, &it))) {
75*6a54128fSAndroid Build Coastguard Worker fs_free_blocks_range(fs, allocator, &e->blocks);
76*6a54128fSAndroid Build Coastguard Worker delete_block_ranges(&e->blocks);
77*6a54128fSAndroid Build Coastguard Worker }
78*6a54128fSAndroid Build Coastguard Worker ext2fs_hashmap_free(entries);
79*6a54128fSAndroid Build Coastguard Worker }
80*6a54128fSAndroid Build Coastguard Worker fs_free_blocks_bitmap(fs, allocator->dedup_block_map);
81*6a54128fSAndroid Build Coastguard Worker ext2fs_free_block_bitmap(allocator->exclusive_block_map);
82*6a54128fSAndroid Build Coastguard Worker ext2fs_free_block_bitmap(allocator->dedup_block_map);
83*6a54128fSAndroid Build Coastguard Worker free(allocator);
84*6a54128fSAndroid Build Coastguard Worker }
85*6a54128fSAndroid Build Coastguard Worker
86*6a54128fSAndroid Build Coastguard Worker /*
87*6a54128fSAndroid Build Coastguard Worker * Build a bitmap of which blocks are definitely owned by exactly one file in
88*6a54128fSAndroid Build Coastguard Worker * Base FS. Blocks which are not valid or are de-duplicated are skipped. This
89*6a54128fSAndroid Build Coastguard Worker * is called during allocator initialization, to ensure that libext2fs does
90*6a54128fSAndroid Build Coastguard Worker * not allocate which we want to re-use.
91*6a54128fSAndroid Build Coastguard Worker *
92*6a54128fSAndroid Build Coastguard Worker * If a block was allocated in the initial filesystem, it can never be re-used,
93*6a54128fSAndroid Build Coastguard Worker * so it will appear in neither the exclusive or dedup set. If a block is used
94*6a54128fSAndroid Build Coastguard Worker * by multiple files, it will be removed from the owned set and instead added
95*6a54128fSAndroid Build Coastguard Worker * to the dedup set.
96*6a54128fSAndroid Build Coastguard Worker *
97*6a54128fSAndroid Build Coastguard Worker * The dedup set is not removed from fs->block_map. This allows us to re-use
98*6a54128fSAndroid Build Coastguard Worker * dedup blocks separately and not have them be allocated outside of file data.
99*6a54128fSAndroid Build Coastguard Worker *
100*6a54128fSAndroid Build Coastguard Worker * This function returns non-zero if the block was owned, and 0 otherwise.
101*6a54128fSAndroid Build Coastguard Worker */
fs_reserve_block(ext2_filsys fs,struct base_fs_allocator * allocator,blk64_t block)102*6a54128fSAndroid Build Coastguard Worker static int fs_reserve_block(ext2_filsys fs,
103*6a54128fSAndroid Build Coastguard Worker struct base_fs_allocator *allocator,
104*6a54128fSAndroid Build Coastguard Worker blk64_t block)
105*6a54128fSAndroid Build Coastguard Worker {
106*6a54128fSAndroid Build Coastguard Worker ext2fs_block_bitmap exclusive_map = allocator->exclusive_block_map;
107*6a54128fSAndroid Build Coastguard Worker ext2fs_block_bitmap dedup_map = allocator->dedup_block_map;
108*6a54128fSAndroid Build Coastguard Worker
109*6a54128fSAndroid Build Coastguard Worker if (block >= ext2fs_blocks_count(fs->super))
110*6a54128fSAndroid Build Coastguard Worker return 0;
111*6a54128fSAndroid Build Coastguard Worker
112*6a54128fSAndroid Build Coastguard Worker if (ext2fs_test_block_bitmap2(fs->block_map, block)) {
113*6a54128fSAndroid Build Coastguard Worker if (!ext2fs_test_block_bitmap2(exclusive_map, block))
114*6a54128fSAndroid Build Coastguard Worker return 0;
115*6a54128fSAndroid Build Coastguard Worker ext2fs_unmark_block_bitmap2(exclusive_map, block);
116*6a54128fSAndroid Build Coastguard Worker ext2fs_mark_block_bitmap2(dedup_map, block);
117*6a54128fSAndroid Build Coastguard Worker return 0;
118*6a54128fSAndroid Build Coastguard Worker } else {
119*6a54128fSAndroid Build Coastguard Worker ext2fs_mark_block_bitmap2(fs->block_map, block);
120*6a54128fSAndroid Build Coastguard Worker ext2fs_mark_block_bitmap2(exclusive_map, block);
121*6a54128fSAndroid Build Coastguard Worker return 1;
122*6a54128fSAndroid Build Coastguard Worker }
123*6a54128fSAndroid Build Coastguard Worker }
124*6a54128fSAndroid Build Coastguard Worker
125*6a54128fSAndroid Build Coastguard Worker /*
126*6a54128fSAndroid Build Coastguard Worker * Walk the requested block list and reserve blocks, either into the owned
127*6a54128fSAndroid Build Coastguard Worker * pool or the dedup pool as appropriate. We stop once the file has enough
128*6a54128fSAndroid Build Coastguard Worker * owned blocks to satisfy |file_size|. This allows any extra blocks to be
129*6a54128fSAndroid Build Coastguard Worker * re-used, since otherwise a large block movement between files could
130*6a54128fSAndroid Build Coastguard Worker * trigger block allocation errors.
131*6a54128fSAndroid Build Coastguard Worker */
fs_reserve_blocks_range(ext2_filsys fs,struct base_fs_allocator * allocator,struct block_range_list * list,off_t file_size)132*6a54128fSAndroid Build Coastguard Worker static void fs_reserve_blocks_range(ext2_filsys fs,
133*6a54128fSAndroid Build Coastguard Worker struct base_fs_allocator *allocator,
134*6a54128fSAndroid Build Coastguard Worker struct block_range_list *list,
135*6a54128fSAndroid Build Coastguard Worker off_t file_size)
136*6a54128fSAndroid Build Coastguard Worker {
137*6a54128fSAndroid Build Coastguard Worker blk64_t block;
138*6a54128fSAndroid Build Coastguard Worker off_t blocks_needed;
139*6a54128fSAndroid Build Coastguard Worker off_t blocks_acquired = 0;
140*6a54128fSAndroid Build Coastguard Worker struct block_range *blocks = list->head;
141*6a54128fSAndroid Build Coastguard Worker
142*6a54128fSAndroid Build Coastguard Worker blocks_needed = file_size + (fs->blocksize - 1);
143*6a54128fSAndroid Build Coastguard Worker blocks_needed /= fs->blocksize;
144*6a54128fSAndroid Build Coastguard Worker
145*6a54128fSAndroid Build Coastguard Worker while (blocks) {
146*6a54128fSAndroid Build Coastguard Worker for (block = blocks->start; block <= blocks->end; block++) {
147*6a54128fSAndroid Build Coastguard Worker if (fs_reserve_block(fs, allocator, block))
148*6a54128fSAndroid Build Coastguard Worker blocks_acquired++;
149*6a54128fSAndroid Build Coastguard Worker if (blocks_acquired >= blocks_needed)
150*6a54128fSAndroid Build Coastguard Worker return;
151*6a54128fSAndroid Build Coastguard Worker }
152*6a54128fSAndroid Build Coastguard Worker blocks = blocks->next;
153*6a54128fSAndroid Build Coastguard Worker }
154*6a54128fSAndroid Build Coastguard Worker }
155*6a54128fSAndroid Build Coastguard Worker
156*6a54128fSAndroid Build Coastguard Worker /*
157*6a54128fSAndroid Build Coastguard Worker * For each file in the base FS map, ensure that its blocks are reserved in
158*6a54128fSAndroid Build Coastguard Worker * the actual block map. This prevents libext2fs from allocating them for
159*6a54128fSAndroid Build Coastguard Worker * general purpose use, and ensures that if the file needs data blocks, they
160*6a54128fSAndroid Build Coastguard Worker * can be re-acquired exclusively for that file.
161*6a54128fSAndroid Build Coastguard Worker *
162*6a54128fSAndroid Build Coastguard Worker * If a file in the base map is missing, or not a regular file in the new
163*6a54128fSAndroid Build Coastguard Worker * filesystem, then it's skipped to ensure that its blocks are reusable.
164*6a54128fSAndroid Build Coastguard Worker */
fs_reserve_blocks(ext2_filsys fs,struct base_fs_allocator * allocator,const char * src_dir)165*6a54128fSAndroid Build Coastguard Worker static errcode_t fs_reserve_blocks(ext2_filsys fs,
166*6a54128fSAndroid Build Coastguard Worker struct base_fs_allocator *allocator,
167*6a54128fSAndroid Build Coastguard Worker const char *src_dir)
168*6a54128fSAndroid Build Coastguard Worker {
169*6a54128fSAndroid Build Coastguard Worker int nbytes;
170*6a54128fSAndroid Build Coastguard Worker char full_path[PATH_MAX];
171*6a54128fSAndroid Build Coastguard Worker const char *sep = "/";
172*6a54128fSAndroid Build Coastguard Worker struct stat st;
173*6a54128fSAndroid Build Coastguard Worker struct basefs_entry *e;
174*6a54128fSAndroid Build Coastguard Worker struct ext2fs_hashmap_entry *it = NULL;
175*6a54128fSAndroid Build Coastguard Worker struct ext2fs_hashmap *entries = allocator->entries;
176*6a54128fSAndroid Build Coastguard Worker
177*6a54128fSAndroid Build Coastguard Worker if (strlen(src_dir) && src_dir[strlen(src_dir) - 1] == '/')
178*6a54128fSAndroid Build Coastguard Worker sep = "";
179*6a54128fSAndroid Build Coastguard Worker
180*6a54128fSAndroid Build Coastguard Worker while ((e = ext2fs_hashmap_iter_in_order(entries, &it))) {
181*6a54128fSAndroid Build Coastguard Worker nbytes = snprintf(full_path, sizeof(full_path), "%s%s%s",
182*6a54128fSAndroid Build Coastguard Worker src_dir, sep, e->path);
183*6a54128fSAndroid Build Coastguard Worker if (nbytes >= sizeof(full_path))
184*6a54128fSAndroid Build Coastguard Worker return ENAMETOOLONG;
185*6a54128fSAndroid Build Coastguard Worker if (lstat(full_path, &st) || !S_ISREG(st.st_mode))
186*6a54128fSAndroid Build Coastguard Worker continue;
187*6a54128fSAndroid Build Coastguard Worker fs_reserve_blocks_range(fs, allocator, &e->blocks, st.st_size);
188*6a54128fSAndroid Build Coastguard Worker }
189*6a54128fSAndroid Build Coastguard Worker return 0;
190*6a54128fSAndroid Build Coastguard Worker }
191*6a54128fSAndroid Build Coastguard Worker
base_fs_alloc_load(ext2_filsys fs,const char * file,const char * mountpoint,const char * src_dir)192*6a54128fSAndroid Build Coastguard Worker errcode_t base_fs_alloc_load(ext2_filsys fs, const char *file,
193*6a54128fSAndroid Build Coastguard Worker const char *mountpoint, const char *src_dir)
194*6a54128fSAndroid Build Coastguard Worker {
195*6a54128fSAndroid Build Coastguard Worker errcode_t retval = 0;
196*6a54128fSAndroid Build Coastguard Worker struct base_fs_allocator *allocator;
197*6a54128fSAndroid Build Coastguard Worker
198*6a54128fSAndroid Build Coastguard Worker allocator = calloc(1, sizeof(*allocator));
199*6a54128fSAndroid Build Coastguard Worker if (!allocator) {
200*6a54128fSAndroid Build Coastguard Worker retval = ENOMEM;
201*6a54128fSAndroid Build Coastguard Worker goto out;
202*6a54128fSAndroid Build Coastguard Worker }
203*6a54128fSAndroid Build Coastguard Worker
204*6a54128fSAndroid Build Coastguard Worker retval = ext2fs_read_bitmaps(fs);
205*6a54128fSAndroid Build Coastguard Worker if (retval)
206*6a54128fSAndroid Build Coastguard Worker goto err_load;
207*6a54128fSAndroid Build Coastguard Worker
208*6a54128fSAndroid Build Coastguard Worker allocator->cur_entry = NULL;
209*6a54128fSAndroid Build Coastguard Worker allocator->entries = basefs_parse(file, mountpoint);
210*6a54128fSAndroid Build Coastguard Worker if (!allocator->entries) {
211*6a54128fSAndroid Build Coastguard Worker retval = EIO;
212*6a54128fSAndroid Build Coastguard Worker goto err_load;
213*6a54128fSAndroid Build Coastguard Worker }
214*6a54128fSAndroid Build Coastguard Worker retval = ext2fs_allocate_block_bitmap(fs, "exclusive map",
215*6a54128fSAndroid Build Coastguard Worker &allocator->exclusive_block_map);
216*6a54128fSAndroid Build Coastguard Worker if (retval)
217*6a54128fSAndroid Build Coastguard Worker goto err_load;
218*6a54128fSAndroid Build Coastguard Worker retval = ext2fs_allocate_block_bitmap(fs, "dedup map",
219*6a54128fSAndroid Build Coastguard Worker &allocator->dedup_block_map);
220*6a54128fSAndroid Build Coastguard Worker if (retval)
221*6a54128fSAndroid Build Coastguard Worker goto err_load;
222*6a54128fSAndroid Build Coastguard Worker
223*6a54128fSAndroid Build Coastguard Worker retval = fs_reserve_blocks(fs, allocator, src_dir);
224*6a54128fSAndroid Build Coastguard Worker if (retval)
225*6a54128fSAndroid Build Coastguard Worker goto err_load;
226*6a54128fSAndroid Build Coastguard Worker
227*6a54128fSAndroid Build Coastguard Worker /* Override the default allocator */
228*6a54128fSAndroid Build Coastguard Worker fs->get_alloc_block2 = basefs_block_allocator;
229*6a54128fSAndroid Build Coastguard Worker fs->priv_data = allocator;
230*6a54128fSAndroid Build Coastguard Worker
231*6a54128fSAndroid Build Coastguard Worker goto out;
232*6a54128fSAndroid Build Coastguard Worker
233*6a54128fSAndroid Build Coastguard Worker err_load:
234*6a54128fSAndroid Build Coastguard Worker basefs_allocator_free(fs, allocator);
235*6a54128fSAndroid Build Coastguard Worker out:
236*6a54128fSAndroid Build Coastguard Worker return retval;
237*6a54128fSAndroid Build Coastguard Worker }
238*6a54128fSAndroid Build Coastguard Worker
239*6a54128fSAndroid Build Coastguard Worker /* Try and acquire the next usable block from the Base FS map. */
get_next_block(ext2_filsys fs,struct base_fs_allocator * allocator,struct block_range_list * list,blk64_t * ret)240*6a54128fSAndroid Build Coastguard Worker static errcode_t get_next_block(ext2_filsys fs, struct base_fs_allocator *allocator,
241*6a54128fSAndroid Build Coastguard Worker struct block_range_list* list, blk64_t *ret)
242*6a54128fSAndroid Build Coastguard Worker {
243*6a54128fSAndroid Build Coastguard Worker blk64_t block;
244*6a54128fSAndroid Build Coastguard Worker ext2fs_block_bitmap exclusive_map = allocator->exclusive_block_map;
245*6a54128fSAndroid Build Coastguard Worker ext2fs_block_bitmap dedup_map = allocator->dedup_block_map;
246*6a54128fSAndroid Build Coastguard Worker
247*6a54128fSAndroid Build Coastguard Worker if (!list->head)
248*6a54128fSAndroid Build Coastguard Worker return EXT2_ET_BLOCK_ALLOC_FAIL;
249*6a54128fSAndroid Build Coastguard Worker
250*6a54128fSAndroid Build Coastguard Worker block = consume_next_block(list);
251*6a54128fSAndroid Build Coastguard Worker if (block >= ext2fs_blocks_count(fs->super))
252*6a54128fSAndroid Build Coastguard Worker return EXT2_ET_BLOCK_ALLOC_FAIL;
253*6a54128fSAndroid Build Coastguard Worker if (ext2fs_test_block_bitmap2(exclusive_map, block)) {
254*6a54128fSAndroid Build Coastguard Worker ext2fs_unmark_block_bitmap2(exclusive_map, block);
255*6a54128fSAndroid Build Coastguard Worker *ret = block;
256*6a54128fSAndroid Build Coastguard Worker return 0;
257*6a54128fSAndroid Build Coastguard Worker }
258*6a54128fSAndroid Build Coastguard Worker if (ext2fs_test_block_bitmap2(dedup_map, block)) {
259*6a54128fSAndroid Build Coastguard Worker ext2fs_unmark_block_bitmap2(dedup_map, block);
260*6a54128fSAndroid Build Coastguard Worker *ret = block;
261*6a54128fSAndroid Build Coastguard Worker return 0;
262*6a54128fSAndroid Build Coastguard Worker }
263*6a54128fSAndroid Build Coastguard Worker return EXT2_ET_BLOCK_ALLOC_FAIL;
264*6a54128fSAndroid Build Coastguard Worker }
265*6a54128fSAndroid Build Coastguard Worker
266*6a54128fSAndroid Build Coastguard Worker /*
267*6a54128fSAndroid Build Coastguard Worker * BaseFS lists blocks in logical block order. However, the allocator hook is
268*6a54128fSAndroid Build Coastguard Worker * only called if a block needs to be allocated. In the case of a deduplicated
269*6a54128fSAndroid Build Coastguard Worker * block, or a hole, the hook is not invoked. This means the next block
270*6a54128fSAndroid Build Coastguard Worker * allocation request will be out of sequence. For example, consider if BaseFS
271*6a54128fSAndroid Build Coastguard Worker * specifies the following (0 being a hole):
272*6a54128fSAndroid Build Coastguard Worker * 1 2 3 0 4 5
273*6a54128fSAndroid Build Coastguard Worker *
274*6a54128fSAndroid Build Coastguard Worker * If the new file has a hole at logical block 0, we could accidentally
275*6a54128fSAndroid Build Coastguard Worker * shift the entire expected block list as follows:
276*6a54128fSAndroid Build Coastguard Worker * 0 1 2 0 3 4
277*6a54128fSAndroid Build Coastguard Worker *
278*6a54128fSAndroid Build Coastguard Worker * To account for this, we track the next expected logical block in the
279*6a54128fSAndroid Build Coastguard Worker * allocator. If the current request is for a later logical block, we skip and
280*6a54128fSAndroid Build Coastguard Worker * free the intermediate physical blocks that would have been allocated. This
281*6a54128fSAndroid Build Coastguard Worker * ensures the original block assignment is respected.
282*6a54128fSAndroid Build Coastguard Worker */
skip_blocks(ext2_filsys fs,struct base_fs_allocator * allocator,struct blk_alloc_ctx * ctx)283*6a54128fSAndroid Build Coastguard Worker static void skip_blocks(ext2_filsys fs, struct base_fs_allocator *allocator,
284*6a54128fSAndroid Build Coastguard Worker struct blk_alloc_ctx *ctx)
285*6a54128fSAndroid Build Coastguard Worker {
286*6a54128fSAndroid Build Coastguard Worker blk64_t block;
287*6a54128fSAndroid Build Coastguard Worker struct block_range_list *list = &allocator->cur_entry->blocks;
288*6a54128fSAndroid Build Coastguard Worker ext2fs_block_bitmap exclusive_map = allocator->exclusive_block_map;
289*6a54128fSAndroid Build Coastguard Worker
290*6a54128fSAndroid Build Coastguard Worker while (list->head && allocator->next_lblk < ctx->lblk) {
291*6a54128fSAndroid Build Coastguard Worker block = consume_next_block(list);
292*6a54128fSAndroid Build Coastguard Worker if (block >= ext2fs_blocks_count(fs->super))
293*6a54128fSAndroid Build Coastguard Worker continue;
294*6a54128fSAndroid Build Coastguard Worker if (ext2fs_test_block_bitmap2(exclusive_map, block)) {
295*6a54128fSAndroid Build Coastguard Worker ext2fs_unmark_block_bitmap2(exclusive_map, block);
296*6a54128fSAndroid Build Coastguard Worker ext2fs_unmark_block_bitmap2(fs->block_map, block);
297*6a54128fSAndroid Build Coastguard Worker }
298*6a54128fSAndroid Build Coastguard Worker allocator->next_lblk++;
299*6a54128fSAndroid Build Coastguard Worker }
300*6a54128fSAndroid Build Coastguard Worker }
301*6a54128fSAndroid Build Coastguard Worker
basefs_block_allocator(ext2_filsys fs,blk64_t goal,blk64_t * ret,struct blk_alloc_ctx * ctx)302*6a54128fSAndroid Build Coastguard Worker static errcode_t basefs_block_allocator(ext2_filsys fs, blk64_t goal,
303*6a54128fSAndroid Build Coastguard Worker blk64_t *ret, struct blk_alloc_ctx *ctx)
304*6a54128fSAndroid Build Coastguard Worker {
305*6a54128fSAndroid Build Coastguard Worker errcode_t retval;
306*6a54128fSAndroid Build Coastguard Worker struct base_fs_allocator *allocator = fs->priv_data;
307*6a54128fSAndroid Build Coastguard Worker struct basefs_entry *e = allocator->cur_entry;
308*6a54128fSAndroid Build Coastguard Worker ext2fs_block_bitmap dedup_map = allocator->dedup_block_map;
309*6a54128fSAndroid Build Coastguard Worker
310*6a54128fSAndroid Build Coastguard Worker if (e && ctx && (ctx->flags & BLOCK_ALLOC_DATA)) {
311*6a54128fSAndroid Build Coastguard Worker if (allocator->next_lblk < ctx->lblk)
312*6a54128fSAndroid Build Coastguard Worker skip_blocks(fs, allocator, ctx);
313*6a54128fSAndroid Build Coastguard Worker allocator->next_lblk = ctx->lblk + 1;
314*6a54128fSAndroid Build Coastguard Worker
315*6a54128fSAndroid Build Coastguard Worker if (!get_next_block(fs, allocator, &e->blocks, ret))
316*6a54128fSAndroid Build Coastguard Worker return 0;
317*6a54128fSAndroid Build Coastguard Worker }
318*6a54128fSAndroid Build Coastguard Worker
319*6a54128fSAndroid Build Coastguard Worker retval = ext2fs_new_block2(fs, goal, fs->block_map, ret);
320*6a54128fSAndroid Build Coastguard Worker if (!retval) {
321*6a54128fSAndroid Build Coastguard Worker ext2fs_mark_block_bitmap2(fs->block_map, *ret);
322*6a54128fSAndroid Build Coastguard Worker return 0;
323*6a54128fSAndroid Build Coastguard Worker }
324*6a54128fSAndroid Build Coastguard Worker if (retval != EXT2_ET_BLOCK_ALLOC_FAIL)
325*6a54128fSAndroid Build Coastguard Worker return retval;
326*6a54128fSAndroid Build Coastguard Worker
327*6a54128fSAndroid Build Coastguard Worker /* Try to steal a block from the dedup pool. */
328*6a54128fSAndroid Build Coastguard Worker retval = ext2fs_find_first_set_block_bitmap2(dedup_map,
329*6a54128fSAndroid Build Coastguard Worker fs->super->s_first_data_block,
330*6a54128fSAndroid Build Coastguard Worker ext2fs_blocks_count(fs->super) - 1, ret);
331*6a54128fSAndroid Build Coastguard Worker if (!retval) {
332*6a54128fSAndroid Build Coastguard Worker ext2fs_unmark_block_bitmap2(dedup_map, *ret);
333*6a54128fSAndroid Build Coastguard Worker return 0;
334*6a54128fSAndroid Build Coastguard Worker }
335*6a54128fSAndroid Build Coastguard Worker
336*6a54128fSAndroid Build Coastguard Worker /*
337*6a54128fSAndroid Build Coastguard Worker * As a last resort, take any block from our file's list. This
338*6a54128fSAndroid Build Coastguard Worker * risks bloating the diff, but means we are more likely to
339*6a54128fSAndroid Build Coastguard Worker * successfully build an image.
340*6a54128fSAndroid Build Coastguard Worker */
341*6a54128fSAndroid Build Coastguard Worker while (e->blocks.head) {
342*6a54128fSAndroid Build Coastguard Worker if (!get_next_block(fs, allocator, &e->blocks, ret))
343*6a54128fSAndroid Build Coastguard Worker return 0;
344*6a54128fSAndroid Build Coastguard Worker }
345*6a54128fSAndroid Build Coastguard Worker return EXT2_ET_BLOCK_ALLOC_FAIL;
346*6a54128fSAndroid Build Coastguard Worker }
347*6a54128fSAndroid Build Coastguard Worker
base_fs_alloc_cleanup(ext2_filsys fs)348*6a54128fSAndroid Build Coastguard Worker void base_fs_alloc_cleanup(ext2_filsys fs)
349*6a54128fSAndroid Build Coastguard Worker {
350*6a54128fSAndroid Build Coastguard Worker basefs_allocator_free(fs, fs->priv_data);
351*6a54128fSAndroid Build Coastguard Worker fs->priv_data = NULL;
352*6a54128fSAndroid Build Coastguard Worker fs->get_alloc_block2 = NULL;
353*6a54128fSAndroid Build Coastguard Worker }
354*6a54128fSAndroid Build Coastguard Worker
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)355*6a54128fSAndroid Build Coastguard Worker errcode_t base_fs_alloc_set_target(ext2_filsys fs, const char *target_path,
356*6a54128fSAndroid Build Coastguard Worker const char *name EXT2FS_ATTR((unused)),
357*6a54128fSAndroid Build Coastguard Worker ext2_ino_t parent_ino EXT2FS_ATTR((unused)),
358*6a54128fSAndroid Build Coastguard Worker ext2_ino_t root EXT2FS_ATTR((unused)), mode_t mode)
359*6a54128fSAndroid Build Coastguard Worker {
360*6a54128fSAndroid Build Coastguard Worker struct base_fs_allocator *allocator = fs->priv_data;
361*6a54128fSAndroid Build Coastguard Worker
362*6a54128fSAndroid Build Coastguard Worker if (mode != S_IFREG)
363*6a54128fSAndroid Build Coastguard Worker return 0;
364*6a54128fSAndroid Build Coastguard Worker
365*6a54128fSAndroid Build Coastguard Worker if (allocator) {
366*6a54128fSAndroid Build Coastguard Worker allocator->cur_entry = ext2fs_hashmap_lookup(allocator->entries,
367*6a54128fSAndroid Build Coastguard Worker target_path,
368*6a54128fSAndroid Build Coastguard Worker strlen(target_path));
369*6a54128fSAndroid Build Coastguard Worker allocator->next_lblk = 0;
370*6a54128fSAndroid Build Coastguard Worker }
371*6a54128fSAndroid Build Coastguard Worker return 0;
372*6a54128fSAndroid Build Coastguard Worker }
373*6a54128fSAndroid Build Coastguard Worker
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)374*6a54128fSAndroid Build Coastguard Worker errcode_t base_fs_alloc_unset_target(ext2_filsys fs,
375*6a54128fSAndroid Build Coastguard Worker const char *target_path EXT2FS_ATTR((unused)),
376*6a54128fSAndroid Build Coastguard Worker const char *name EXT2FS_ATTR((unused)),
377*6a54128fSAndroid Build Coastguard Worker ext2_ino_t parent_ino EXT2FS_ATTR((unused)),
378*6a54128fSAndroid Build Coastguard Worker ext2_ino_t root EXT2FS_ATTR((unused)), mode_t mode)
379*6a54128fSAndroid Build Coastguard Worker {
380*6a54128fSAndroid Build Coastguard Worker struct base_fs_allocator *allocator = fs->priv_data;
381*6a54128fSAndroid Build Coastguard Worker
382*6a54128fSAndroid Build Coastguard Worker if (!allocator || !allocator->cur_entry || mode != S_IFREG)
383*6a54128fSAndroid Build Coastguard Worker return 0;
384*6a54128fSAndroid Build Coastguard Worker
385*6a54128fSAndroid Build Coastguard Worker fs_free_blocks_range(fs, allocator, &allocator->cur_entry->blocks);
386*6a54128fSAndroid Build Coastguard Worker delete_block_ranges(&allocator->cur_entry->blocks);
387*6a54128fSAndroid Build Coastguard Worker return 0;
388*6a54128fSAndroid Build Coastguard Worker }
389