aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Anderson <dvander@google.com>2019-12-06 16:48:52 -0800
committerTheodore Ts'o <tytso@mit.edu>2020-01-01 13:41:35 -0500
commit67467ea5d742b05f7f3ccbee87aaa65656685e0d (patch)
tree3b6b92f64613ca8c9f2bd8fb99eb5e2f25c8b5e7
parent0f3291fdf14f84e928930a671d41dd69d674b4ff (diff)
downloade2fsprogs-67467ea5d742b05f7f3ccbee87aaa65656685e0d.tar.gz
AOSP: e2fsdroid: Skip Base FS entries that no longer exist.
Don't reserve blocks in the base map if the file does not exist in the target image. This can happen if a file is removed or renamed in between two builds. If the removed file is quite large, skipping it is important since otherwise it will prevent blocks from being allocated for new files. Bug: 145316683 Test: e2fsdroid with dynamic partitions Change-Id: I63a9372c58adeaae3e1235fd92fed78a284ed391 From AOSP commit: 2b6646a3d2a7dd9972275cb829239ae033762da5
-rw-r--r--contrib/android/basefs_allocator.c52
-rw-r--r--contrib/android/basefs_allocator.h2
-rw-r--r--contrib/android/e2fsdroid.c3
3 files changed, 46 insertions, 11 deletions
diff --git a/contrib/android/basefs_allocator.c b/contrib/android/basefs_allocator.c
index 3fe42a094..658a75147 100644
--- a/contrib/android/basefs_allocator.c
+++ b/contrib/android/basefs_allocator.c
@@ -1,3 +1,4 @@
+#include <limits.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "basefs_allocator.h"
@@ -111,20 +112,39 @@ static void fs_reserve_blocks_range(ext2_filsys fs,
* the actual block map. This prevents libext2fs from allocating them for
* general purpose use, and ensures that if the file needs data blocks, they
* can be re-acquired exclusively for that file.
+ *
+ * If a file in the base map is missing, or not a regular file in the new
+ * filesystem, then it's skipped to ensure that its blocks are reusable.
*/
-static void fs_reserve_blocks(ext2_filsys fs,
- struct base_fs_allocator *allocator)
+static errcode_t fs_reserve_blocks(ext2_filsys fs,
+ struct base_fs_allocator *allocator,
+ const char *src_dir)
{
+ int nbytes;
+ char full_path[PATH_MAX];
+ const char *sep = "/";
+ struct stat st;
struct basefs_entry *e;
struct ext2fs_hashmap_entry *it = NULL;
struct ext2fs_hashmap *entries = allocator->entries;
- while ((e = ext2fs_hashmap_iter_in_order(entries, &it)))
+ if (strlen(src_dir) && src_dir[strlen(src_dir) - 1] == '/')
+ sep = "";
+
+ while ((e = ext2fs_hashmap_iter_in_order(entries, &it))) {
+ nbytes = snprintf(full_path, sizeof(full_path), "%s%s%s",
+ src_dir, sep, e->path);
+ if (nbytes >= sizeof(full_path))
+ return ENAMETOOLONG;
+ if (lstat(full_path, &st) || !S_ISREG(st.st_mode))
+ continue;
fs_reserve_blocks_range(fs, allocator, &e->blocks);
+ }
+ return 0;
}
errcode_t base_fs_alloc_load(ext2_filsys fs, const char *file,
- const char *mountpoint)
+ const char *mountpoint, const char *src_dir)
{
errcode_t retval = 0;
struct base_fs_allocator *allocator;
@@ -154,7 +174,9 @@ errcode_t base_fs_alloc_load(ext2_filsys fs, const char *file,
if (retval)
goto err_load;
- fs_reserve_blocks(fs, allocator);
+ retval = fs_reserve_blocks(fs, allocator, src_dir);
+ if (retval)
+ goto err_load;
/* Override the default allocator */
fs->get_alloc_block2 = basefs_block_allocator;
@@ -200,6 +222,7 @@ static errcode_t basefs_block_allocator(ext2_filsys fs, blk64_t goal,
errcode_t retval;
struct base_fs_allocator *allocator = fs->priv_data;
struct basefs_entry *e = allocator->cur_entry;
+ ext2fs_block_bitmap dedup_map = allocator->dedup_block_map;
if (e && ctx && (ctx->flags & BLOCK_ALLOC_DATA)) {
if (!get_next_block(fs, allocator, &e->blocks, ret))
@@ -207,10 +230,21 @@ static errcode_t basefs_block_allocator(ext2_filsys fs, blk64_t goal,
}
retval = ext2fs_new_block2(fs, goal, fs->block_map, ret);
- if (retval)
- return retval;
- ext2fs_mark_block_bitmap2(fs->block_map, *ret);
- return 0;
+ if (!retval) {
+ ext2fs_mark_block_bitmap2(fs->block_map, *ret);
+ return 0;
+ }
+ if (retval == EXT2_ET_BLOCK_ALLOC_FAIL) {
+ /* Try to steal a block from the dedup pool. */
+ retval = ext2fs_find_first_set_block_bitmap2(dedup_map,
+ fs->super->s_first_data_block,
+ ext2fs_blocks_count(fs->super) - 1, ret);
+ if (!retval) {
+ ext2fs_unmark_block_bitmap2(dedup_map, *ret);
+ return 0;
+ }
+ }
+ return retval;
}
void base_fs_alloc_cleanup(ext2_filsys fs)
diff --git a/contrib/android/basefs_allocator.h b/contrib/android/basefs_allocator.h
index f1109cd61..6d1c65e30 100644
--- a/contrib/android/basefs_allocator.h
+++ b/contrib/android/basefs_allocator.h
@@ -5,7 +5,7 @@
# include <ext2fs/ext2fs.h>
errcode_t base_fs_alloc_load(ext2_filsys fs, const char *file,
- const char *mountpoint);
+ const char *mountpoint, const char *src_dir);
void base_fs_alloc_cleanup(ext2_filsys fs);
errcode_t base_fs_alloc_set_target(ext2_filsys fs, const char *target_path,
diff --git a/contrib/android/e2fsdroid.c b/contrib/android/e2fsdroid.c
index 3264a99fb..1beb1e25b 100644
--- a/contrib/android/e2fsdroid.c
+++ b/contrib/android/e2fsdroid.c
@@ -301,7 +301,8 @@ int main(int argc, char *argv[])
if (src_dir) {
ext2fs_read_bitmaps(fs);
if (basefs_in) {
- retval = base_fs_alloc_load(fs, basefs_in, mountpoint);
+ retval = base_fs_alloc_load(fs, basefs_in, mountpoint,
+ src_dir);
if (retval) {
com_err(prog_name, retval, "%s",
"while reading base_fs file");