Loading debuggerd/libdebuggerd/tombstone.cpp +1 −1 Original line number Diff line number Diff line Loading @@ -316,7 +316,7 @@ static void dump_all_maps(log_t* log, unwindstack::Unwinder* unwinder, uint64_t std::shared_ptr<unwindstack::Memory>& process_memory = unwinder->GetProcessMemory(); std::string line; for (unwindstack::MapInfo* map_info : *maps) { for (auto const& map_info : *maps) { line = " "; if (print_fault_address_marker) { if (addr < map_info->start) { Loading fs_mgr/fs_mgr_remount.cpp +26 −13 Original line number Diff line number Diff line Loading @@ -263,35 +263,43 @@ int main(int argc, char* argv[]) { // Check verity and optionally setup overlayfs backing. auto reboot_later = false; auto uses_overlayfs = fs_mgr_overlayfs_valid() != OverlayfsValidResult::kNotSupported; for (auto it = partitions.begin(); it != partitions.end();) { auto& entry = *it; auto& mount_point = entry.mount_point; if (fs_mgr_is_verity_enabled(entry)) { LOG(WARNING) << "Verity enabled on " << mount_point; if (can_reboot && (android::base::GetProperty("ro.boot.vbmeta.devices_state", "") != "locked")) { retval = VERITY_PARTITION; if (android::base::GetProperty("ro.boot.vbmeta.devices_state", "") != "locked") { if (AvbOps* ops = avb_ops_user_new()) { auto ret = avb_user_verity_set( ops, android::base::GetProperty("ro.boot.slot_suffix", "").c_str(), false); avb_ops_user_free(ops); if (ret) { if (fs_mgr_overlayfs_valid() == OverlayfsValidResult::kNotSupported) { retval = VERITY_PARTITION; LOG(WARNING) << "Disable verity for " << mount_point; reboot_later = can_reboot; if (reboot_later) { // w/o overlayfs available, also check for dedupe reboot_later = true; if (!uses_overlayfs) { ++it; continue; } reboot(false); } } else if (fs_mgr_set_blk_ro(entry.blk_device, false)) { fec::io fh(entry.blk_device.c_str(), O_RDWR); if (fh && fh.set_verity_status(false)) reboot_later = true; if (fh && fh.set_verity_status(false)) { LOG(WARNING) << "Disable verity for " << mount_point; reboot_later = can_reboot; if (reboot_later && !uses_overlayfs) { ++it; continue; } } } } } LOG(ERROR) << "Skipping " << mount_point; retval = VERITY_PARTITION; it = partitions.erase(it); continue; } Loading @@ -318,7 +326,8 @@ int main(int argc, char* argv[]) { } // Mount overlayfs. if (!fs_mgr_overlayfs_mount_all(&partitions)) { errno = 0; if (!fs_mgr_overlayfs_mount_all(&partitions) && errno) { retval = BAD_OVERLAY; PLOG(ERROR) << "Can not mount overlayfs for partitions"; } Loading Loading @@ -346,11 +355,15 @@ int main(int argc, char* argv[]) { break; } if ((mount_point == "/") && (rentry.mount_point == "/system")) { if (blk_device != "/dev/root") blk_device = rentry.blk_device; blk_device = rentry.blk_device; mount_point = "/system"; break; } } if (blk_device == "/dev/root") { auto from_fstab = GetEntryForMountPoint(&fstab, mount_point); if (from_fstab) blk_device = from_fstab->blk_device; } fs_mgr_set_blk_ro(blk_device, false); // Now remount! Loading fs_mgr/libfiemap_writer/Android.bp +7 −3 Original line number Diff line number Diff line Loading @@ -20,13 +20,17 @@ cc_library_static { recovery_available: true, export_include_dirs: ["include"], cflags: [ // TODO(b/121211685): Allows us to create a skeleton of required classes "-Wno-unused-private-field", "-Wno-unused-parameter", "-D_FILE_OFFSET_BITS=64", ], srcs: [ "fiemap_writer.cpp", "split_fiemap_writer.cpp", "utility.cpp", ], static_libs: [ "libext4_utils", ], header_libs: [ Loading fs_mgr/libfiemap_writer/fiemap_writer.cpp +109 −25 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ #include <sys/vfs.h> #include <unistd.h> #include <limits> #include <string> #include <utility> #include <vector> Loading Loading @@ -206,8 +207,13 @@ static bool PerformFileChecks(const std::string& file_path, uint64_t file_size, } // Check if the filesystem is of supported types. // Only ext4 and f2fs are tested and supported. if ((sfs.f_type != EXT4_SUPER_MAGIC) && (sfs.f_type != F2FS_SUPER_MAGIC)) { // Only ext4, f2fs, and vfat are tested and supported. switch (sfs.f_type) { case EXT4_SUPER_MAGIC: case F2FS_SUPER_MAGIC: case MSDOS_SUPER_MAGIC: break; default: LOG(ERROR) << "Unsupported file system type: 0x" << std::hex << sfs.f_type; return false; } Loading @@ -224,13 +230,45 @@ static bool PerformFileChecks(const std::string& file_path, uint64_t file_size, } static bool AllocateFile(int file_fd, const std::string& file_path, uint64_t blocksz, uint64_t file_size, std::function<bool(uint64_t, uint64_t)> on_progress) { uint64_t file_size, unsigned int fs_type, std::function<bool(uint64_t, uint64_t)> on_progress) { // Reserve space for the file on the file system and write it out to make sure the extents // don't come back unwritten. Return from this function with the kernel file offset set to 0. // If the filesystem is f2fs, then we also PIN the file on disk to make sure the blocks // aren't moved around. if (fallocate64(file_fd, FALLOC_FL_ZERO_RANGE, 0, file_size)) { PLOG(ERROR) << "Failed to allocate space for file: " << file_path << " size: " << file_size; switch (fs_type) { case EXT4_SUPER_MAGIC: case F2FS_SUPER_MAGIC: if (fallocate(file_fd, FALLOC_FL_ZERO_RANGE, 0, file_size)) { PLOG(ERROR) << "Failed to allocate space for file: " << file_path << " size: " << file_size; return false; } break; case MSDOS_SUPER_MAGIC: { // fallocate() is not supported, and not needed, since VFAT does not support holes. // Instead we can perform a much faster allocation. auto offset = TEMP_FAILURE_RETRY(lseek(file_fd, file_size - 1, SEEK_SET)); if (offset < 0) { PLOG(ERROR) << "Failed to lseek " << file_path; return false; } if (offset != file_size - 1) { LOG(ERROR) << "Seek returned wrong offset " << offset << " for file " << file_path; return false; } char buffer[] = {0}; if (!android::base::WriteFully(file_fd, buffer, 1)) { PLOG(ERROR) << "Write failed: " << file_path; return false; } if (on_progress && !on_progress(file_size, file_size)) { return false; } return true; } default: LOG(ERROR) << "Missing fallocate() support for file system " << fs_type; return false; } Loading Loading @@ -286,9 +324,9 @@ static bool AllocateFile(int file_fd, const std::string& file_path, uint64_t blo } static bool PinFile(int file_fd, const std::string& file_path, uint32_t fs_type) { if (fs_type == EXT4_SUPER_MAGIC) { // No pinning necessary for ext4. The blocks, once allocated, are expected // to be fixed. if (fs_type != F2FS_SUPER_MAGIC) { // No pinning necessary for ext4/msdos. The blocks, once allocated, are // expected to be fixed. return true; } Loading Loading @@ -323,9 +361,9 @@ static bool PinFile(int file_fd, const std::string& file_path, uint32_t fs_type) } static bool IsFilePinned(int file_fd, const std::string& file_path, uint32_t fs_type) { if (fs_type == EXT4_SUPER_MAGIC) { // No pinning necessary for ext4. The blocks, once allocated, are expected // to be fixed. if (fs_type != F2FS_SUPER_MAGIC) { // No pinning necessary for ext4 or vfat. The blocks, once allocated, // are expected to be fixed. return true; } Loading Loading @@ -437,6 +475,44 @@ static bool ReadFiemap(int file_fd, const std::string& file_path, return last_extent_seen; } static bool ReadFibmap(int file_fd, const std::string& file_path, std::vector<struct fiemap_extent>* extents) { struct stat s; if (fstat(file_fd, &s)) { PLOG(ERROR) << "Failed to stat " << file_path; return false; } uint64_t num_blocks = (s.st_size + s.st_blksize - 1) / s.st_blksize; if (num_blocks > std::numeric_limits<uint32_t>::max()) { LOG(ERROR) << "Too many blocks for FIBMAP (" << num_blocks << ")"; return false; } for (uint32_t last_block, block_number = 0; block_number < num_blocks; block_number++) { uint32_t block = block_number; if (ioctl(file_fd, FIBMAP, &block)) { PLOG(ERROR) << "Failed to get FIBMAP for file " << file_path; return false; } if (!block) { LOG(ERROR) << "Logical block " << block_number << " is a hole, which is not supported"; return false; } if (!extents->empty() && block == last_block + 1) { extents->back().fe_length++; } else { extents->push_back(fiemap_extent{.fe_logical = block_number, .fe_physical = block, .fe_length = 1, .fe_flags = 0}); } last_block = block; } return true; } FiemapUniquePtr FiemapWriter::Open(const std::string& file_path, uint64_t file_size, bool create, std::function<bool(uint64_t, uint64_t)> progress) { // if 'create' is false, open an existing file and do not truncate. Loading Loading @@ -505,7 +581,7 @@ FiemapUniquePtr FiemapWriter::Open(const std::string& file_path, uint64_t file_s } if (create) { if (!AllocateFile(file_fd, abs_path, blocksz, file_size, std::move(progress))) { if (!AllocateFile(file_fd, abs_path, blocksz, file_size, fs_type, std::move(progress))) { LOG(ERROR) << "Failed to allocate file: " << abs_path << " of size: " << file_size << " bytes"; cleanup(abs_path, create); Loading @@ -522,11 +598,23 @@ FiemapUniquePtr FiemapWriter::Open(const std::string& file_path, uint64_t file_s // now allocate the FiemapWriter and start setting it up FiemapUniquePtr fmap(new FiemapWriter()); switch (fs_type) { case EXT4_SUPER_MAGIC: case F2FS_SUPER_MAGIC: if (!ReadFiemap(file_fd, abs_path, &fmap->extents_)) { LOG(ERROR) << "Failed to read fiemap of file: " << abs_path; cleanup(abs_path, create); return nullptr; } break; case MSDOS_SUPER_MAGIC: if (!ReadFibmap(file_fd, abs_path, &fmap->extents_)) { LOG(ERROR) << "Failed to read fibmap of file: " << abs_path; cleanup(abs_path, create); return nullptr; } break; } fmap->file_path_ = abs_path; fmap->bdev_path_ = bdev_path; Loading @@ -536,14 +624,10 @@ FiemapUniquePtr FiemapWriter::Open(const std::string& file_path, uint64_t file_s fmap->fs_type_ = fs_type; fmap->block_size_ = blocksz; LOG(INFO) << "Successfully created FiemapWriter for file " << abs_path << " on block device " LOG(VERBOSE) << "Successfully created FiemapWriter for file " << abs_path << " on block device " << bdev_path; return fmap; } bool FiemapWriter::Read(off64_t off, uint8_t* buffer, uint64_t size) { return false; } } // namespace fiemap_writer } // namespace android fs_mgr/libfiemap_writer/fiemap_writer_test.cpp +87 −9 Original line number Diff line number Diff line Loading @@ -33,8 +33,10 @@ #include <android-base/unique_fd.h> #include <gtest/gtest.h> #include <libdm/loop_control.h> #include <libfiemap_writer/fiemap_writer.h> #include <libfiemap_writer/split_fiemap_writer.h> #include "utility.h" using namespace std; using namespace std::string_literals; Loading @@ -59,6 +61,24 @@ class FiemapWriterTest : public ::testing::Test { std::string testfile; }; class SplitFiemapTest : public ::testing::Test { protected: void SetUp() override { const ::testing::TestInfo* tinfo = ::testing::UnitTest::GetInstance()->current_test_info(); testfile = gTestDir + "/"s + tinfo->name(); } void TearDown() override { std::string message; if (!SplitFiemap::RemoveSplitFiles(testfile, &message)) { cerr << "Could not remove all split files: " << message; } } // name of the file we use for testing std::string testfile; }; TEST_F(FiemapWriterTest, CreateImpossiblyLargeFile) { // Try creating a file of size ~100TB but aligned to // 512 byte to make sure block alignment tests don't Loading @@ -71,8 +91,7 @@ TEST_F(FiemapWriterTest, CreateImpossiblyLargeFile) { TEST_F(FiemapWriterTest, CreateUnalignedFile) { // Try creating a file of size 4097 bytes which is guaranteed // to be unaligned to all known block sizes. The creation must // fail. // to be unaligned to all known block sizes. FiemapUniquePtr fptr = FiemapWriter::Open(testfile, gBlockSize + 1); ASSERT_NE(fptr, nullptr); ASSERT_EQ(fptr->size(), gBlockSize * 2); Loading @@ -87,10 +106,7 @@ TEST_F(FiemapWriterTest, CheckFilePath) { } TEST_F(FiemapWriterTest, CheckProgress) { std::vector<uint64_t> expected{ 0, gBlockSize, }; std::vector<uint64_t> expected; size_t invocations = 0; auto callback = [&](uint64_t done, uint64_t total) -> bool { EXPECT_LT(invocations, expected.size()); Loading @@ -100,9 +116,22 @@ TEST_F(FiemapWriterTest, CheckProgress) { return true; }; uint32_t fs_type; { auto ptr = FiemapWriter::Open(testfile, gBlockSize, true); ASSERT_NE(ptr, nullptr); fs_type = ptr->fs_type(); } ASSERT_EQ(unlink(testfile.c_str()), 0); if (fs_type != MSDOS_SUPER_MAGIC) { expected.push_back(0); } expected.push_back(gBlockSize); auto ptr = FiemapWriter::Open(testfile, gBlockSize, true, std::move(callback)); EXPECT_NE(ptr, nullptr); EXPECT_EQ(invocations, 2); EXPECT_EQ(invocations, expected.size()); } TEST_F(FiemapWriterTest, CheckPinning) { Loading Loading @@ -159,6 +188,52 @@ TEST_F(FiemapWriterTest, FileDeletedOnError) { EXPECT_EQ(errno, ENOENT); } TEST_F(FiemapWriterTest, MaxBlockSize) { ASSERT_GT(DetermineMaximumFileSize(testfile), 0); } TEST_F(SplitFiemapTest, Create) { auto ptr = SplitFiemap::Create(testfile, 1024 * 768, 1024 * 32); ASSERT_NE(ptr, nullptr); auto extents = ptr->extents(); // Destroy the fiemap, closing file handles. This should not delete them. ptr = nullptr; std::vector<std::string> files; ASSERT_TRUE(SplitFiemap::GetSplitFileList(testfile, &files)); for (const auto& path : files) { EXPECT_EQ(access(path.c_str(), F_OK), 0); } ASSERT_GE(extents.size(), files.size()); } TEST_F(SplitFiemapTest, Open) { { auto ptr = SplitFiemap::Create(testfile, 1024 * 768, 1024 * 32); ASSERT_NE(ptr, nullptr); } auto ptr = SplitFiemap::Open(testfile); ASSERT_NE(ptr, nullptr); auto extents = ptr->extents(); ASSERT_GE(extents.size(), 24); } TEST_F(SplitFiemapTest, DeleteOnFail) { auto ptr = SplitFiemap::Create(testfile, 1024 * 1024 * 10, 1); ASSERT_EQ(ptr, nullptr); std::string first_file = testfile + ".0001"; ASSERT_NE(access(first_file.c_str(), F_OK), 0); ASSERT_EQ(errno, ENOENT); ASSERT_NE(access(testfile.c_str(), F_OK), 0); ASSERT_EQ(errno, ENOENT); } class VerifyBlockWritesExt4 : public ::testing::Test { // 2GB Filesystem and 4k block size by default static constexpr uint64_t block_size = 4096; Loading Loading @@ -273,7 +348,10 @@ int main(int argc, char** argv) { cerr << "unable to create tempdir on " << argv[1] << "\n"; exit(EXIT_FAILURE); } gTestDir = tempdir; if (!android::base::Realpath(tempdir, &gTestDir)) { cerr << "unable to find realpath for " << tempdir; exit(EXIT_FAILURE); } if (argc > 2) { testfile_size = strtoull(argv[2], NULL, 0); Loading Loading
debuggerd/libdebuggerd/tombstone.cpp +1 −1 Original line number Diff line number Diff line Loading @@ -316,7 +316,7 @@ static void dump_all_maps(log_t* log, unwindstack::Unwinder* unwinder, uint64_t std::shared_ptr<unwindstack::Memory>& process_memory = unwinder->GetProcessMemory(); std::string line; for (unwindstack::MapInfo* map_info : *maps) { for (auto const& map_info : *maps) { line = " "; if (print_fault_address_marker) { if (addr < map_info->start) { Loading
fs_mgr/fs_mgr_remount.cpp +26 −13 Original line number Diff line number Diff line Loading @@ -263,35 +263,43 @@ int main(int argc, char* argv[]) { // Check verity and optionally setup overlayfs backing. auto reboot_later = false; auto uses_overlayfs = fs_mgr_overlayfs_valid() != OverlayfsValidResult::kNotSupported; for (auto it = partitions.begin(); it != partitions.end();) { auto& entry = *it; auto& mount_point = entry.mount_point; if (fs_mgr_is_verity_enabled(entry)) { LOG(WARNING) << "Verity enabled on " << mount_point; if (can_reboot && (android::base::GetProperty("ro.boot.vbmeta.devices_state", "") != "locked")) { retval = VERITY_PARTITION; if (android::base::GetProperty("ro.boot.vbmeta.devices_state", "") != "locked") { if (AvbOps* ops = avb_ops_user_new()) { auto ret = avb_user_verity_set( ops, android::base::GetProperty("ro.boot.slot_suffix", "").c_str(), false); avb_ops_user_free(ops); if (ret) { if (fs_mgr_overlayfs_valid() == OverlayfsValidResult::kNotSupported) { retval = VERITY_PARTITION; LOG(WARNING) << "Disable verity for " << mount_point; reboot_later = can_reboot; if (reboot_later) { // w/o overlayfs available, also check for dedupe reboot_later = true; if (!uses_overlayfs) { ++it; continue; } reboot(false); } } else if (fs_mgr_set_blk_ro(entry.blk_device, false)) { fec::io fh(entry.blk_device.c_str(), O_RDWR); if (fh && fh.set_verity_status(false)) reboot_later = true; if (fh && fh.set_verity_status(false)) { LOG(WARNING) << "Disable verity for " << mount_point; reboot_later = can_reboot; if (reboot_later && !uses_overlayfs) { ++it; continue; } } } } } LOG(ERROR) << "Skipping " << mount_point; retval = VERITY_PARTITION; it = partitions.erase(it); continue; } Loading @@ -318,7 +326,8 @@ int main(int argc, char* argv[]) { } // Mount overlayfs. if (!fs_mgr_overlayfs_mount_all(&partitions)) { errno = 0; if (!fs_mgr_overlayfs_mount_all(&partitions) && errno) { retval = BAD_OVERLAY; PLOG(ERROR) << "Can not mount overlayfs for partitions"; } Loading Loading @@ -346,11 +355,15 @@ int main(int argc, char* argv[]) { break; } if ((mount_point == "/") && (rentry.mount_point == "/system")) { if (blk_device != "/dev/root") blk_device = rentry.blk_device; blk_device = rentry.blk_device; mount_point = "/system"; break; } } if (blk_device == "/dev/root") { auto from_fstab = GetEntryForMountPoint(&fstab, mount_point); if (from_fstab) blk_device = from_fstab->blk_device; } fs_mgr_set_blk_ro(blk_device, false); // Now remount! Loading
fs_mgr/libfiemap_writer/Android.bp +7 −3 Original line number Diff line number Diff line Loading @@ -20,13 +20,17 @@ cc_library_static { recovery_available: true, export_include_dirs: ["include"], cflags: [ // TODO(b/121211685): Allows us to create a skeleton of required classes "-Wno-unused-private-field", "-Wno-unused-parameter", "-D_FILE_OFFSET_BITS=64", ], srcs: [ "fiemap_writer.cpp", "split_fiemap_writer.cpp", "utility.cpp", ], static_libs: [ "libext4_utils", ], header_libs: [ Loading
fs_mgr/libfiemap_writer/fiemap_writer.cpp +109 −25 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ #include <sys/vfs.h> #include <unistd.h> #include <limits> #include <string> #include <utility> #include <vector> Loading Loading @@ -206,8 +207,13 @@ static bool PerformFileChecks(const std::string& file_path, uint64_t file_size, } // Check if the filesystem is of supported types. // Only ext4 and f2fs are tested and supported. if ((sfs.f_type != EXT4_SUPER_MAGIC) && (sfs.f_type != F2FS_SUPER_MAGIC)) { // Only ext4, f2fs, and vfat are tested and supported. switch (sfs.f_type) { case EXT4_SUPER_MAGIC: case F2FS_SUPER_MAGIC: case MSDOS_SUPER_MAGIC: break; default: LOG(ERROR) << "Unsupported file system type: 0x" << std::hex << sfs.f_type; return false; } Loading @@ -224,13 +230,45 @@ static bool PerformFileChecks(const std::string& file_path, uint64_t file_size, } static bool AllocateFile(int file_fd, const std::string& file_path, uint64_t blocksz, uint64_t file_size, std::function<bool(uint64_t, uint64_t)> on_progress) { uint64_t file_size, unsigned int fs_type, std::function<bool(uint64_t, uint64_t)> on_progress) { // Reserve space for the file on the file system and write it out to make sure the extents // don't come back unwritten. Return from this function with the kernel file offset set to 0. // If the filesystem is f2fs, then we also PIN the file on disk to make sure the blocks // aren't moved around. if (fallocate64(file_fd, FALLOC_FL_ZERO_RANGE, 0, file_size)) { PLOG(ERROR) << "Failed to allocate space for file: " << file_path << " size: " << file_size; switch (fs_type) { case EXT4_SUPER_MAGIC: case F2FS_SUPER_MAGIC: if (fallocate(file_fd, FALLOC_FL_ZERO_RANGE, 0, file_size)) { PLOG(ERROR) << "Failed to allocate space for file: " << file_path << " size: " << file_size; return false; } break; case MSDOS_SUPER_MAGIC: { // fallocate() is not supported, and not needed, since VFAT does not support holes. // Instead we can perform a much faster allocation. auto offset = TEMP_FAILURE_RETRY(lseek(file_fd, file_size - 1, SEEK_SET)); if (offset < 0) { PLOG(ERROR) << "Failed to lseek " << file_path; return false; } if (offset != file_size - 1) { LOG(ERROR) << "Seek returned wrong offset " << offset << " for file " << file_path; return false; } char buffer[] = {0}; if (!android::base::WriteFully(file_fd, buffer, 1)) { PLOG(ERROR) << "Write failed: " << file_path; return false; } if (on_progress && !on_progress(file_size, file_size)) { return false; } return true; } default: LOG(ERROR) << "Missing fallocate() support for file system " << fs_type; return false; } Loading Loading @@ -286,9 +324,9 @@ static bool AllocateFile(int file_fd, const std::string& file_path, uint64_t blo } static bool PinFile(int file_fd, const std::string& file_path, uint32_t fs_type) { if (fs_type == EXT4_SUPER_MAGIC) { // No pinning necessary for ext4. The blocks, once allocated, are expected // to be fixed. if (fs_type != F2FS_SUPER_MAGIC) { // No pinning necessary for ext4/msdos. The blocks, once allocated, are // expected to be fixed. return true; } Loading Loading @@ -323,9 +361,9 @@ static bool PinFile(int file_fd, const std::string& file_path, uint32_t fs_type) } static bool IsFilePinned(int file_fd, const std::string& file_path, uint32_t fs_type) { if (fs_type == EXT4_SUPER_MAGIC) { // No pinning necessary for ext4. The blocks, once allocated, are expected // to be fixed. if (fs_type != F2FS_SUPER_MAGIC) { // No pinning necessary for ext4 or vfat. The blocks, once allocated, // are expected to be fixed. return true; } Loading Loading @@ -437,6 +475,44 @@ static bool ReadFiemap(int file_fd, const std::string& file_path, return last_extent_seen; } static bool ReadFibmap(int file_fd, const std::string& file_path, std::vector<struct fiemap_extent>* extents) { struct stat s; if (fstat(file_fd, &s)) { PLOG(ERROR) << "Failed to stat " << file_path; return false; } uint64_t num_blocks = (s.st_size + s.st_blksize - 1) / s.st_blksize; if (num_blocks > std::numeric_limits<uint32_t>::max()) { LOG(ERROR) << "Too many blocks for FIBMAP (" << num_blocks << ")"; return false; } for (uint32_t last_block, block_number = 0; block_number < num_blocks; block_number++) { uint32_t block = block_number; if (ioctl(file_fd, FIBMAP, &block)) { PLOG(ERROR) << "Failed to get FIBMAP for file " << file_path; return false; } if (!block) { LOG(ERROR) << "Logical block " << block_number << " is a hole, which is not supported"; return false; } if (!extents->empty() && block == last_block + 1) { extents->back().fe_length++; } else { extents->push_back(fiemap_extent{.fe_logical = block_number, .fe_physical = block, .fe_length = 1, .fe_flags = 0}); } last_block = block; } return true; } FiemapUniquePtr FiemapWriter::Open(const std::string& file_path, uint64_t file_size, bool create, std::function<bool(uint64_t, uint64_t)> progress) { // if 'create' is false, open an existing file and do not truncate. Loading Loading @@ -505,7 +581,7 @@ FiemapUniquePtr FiemapWriter::Open(const std::string& file_path, uint64_t file_s } if (create) { if (!AllocateFile(file_fd, abs_path, blocksz, file_size, std::move(progress))) { if (!AllocateFile(file_fd, abs_path, blocksz, file_size, fs_type, std::move(progress))) { LOG(ERROR) << "Failed to allocate file: " << abs_path << " of size: " << file_size << " bytes"; cleanup(abs_path, create); Loading @@ -522,11 +598,23 @@ FiemapUniquePtr FiemapWriter::Open(const std::string& file_path, uint64_t file_s // now allocate the FiemapWriter and start setting it up FiemapUniquePtr fmap(new FiemapWriter()); switch (fs_type) { case EXT4_SUPER_MAGIC: case F2FS_SUPER_MAGIC: if (!ReadFiemap(file_fd, abs_path, &fmap->extents_)) { LOG(ERROR) << "Failed to read fiemap of file: " << abs_path; cleanup(abs_path, create); return nullptr; } break; case MSDOS_SUPER_MAGIC: if (!ReadFibmap(file_fd, abs_path, &fmap->extents_)) { LOG(ERROR) << "Failed to read fibmap of file: " << abs_path; cleanup(abs_path, create); return nullptr; } break; } fmap->file_path_ = abs_path; fmap->bdev_path_ = bdev_path; Loading @@ -536,14 +624,10 @@ FiemapUniquePtr FiemapWriter::Open(const std::string& file_path, uint64_t file_s fmap->fs_type_ = fs_type; fmap->block_size_ = blocksz; LOG(INFO) << "Successfully created FiemapWriter for file " << abs_path << " on block device " LOG(VERBOSE) << "Successfully created FiemapWriter for file " << abs_path << " on block device " << bdev_path; return fmap; } bool FiemapWriter::Read(off64_t off, uint8_t* buffer, uint64_t size) { return false; } } // namespace fiemap_writer } // namespace android
fs_mgr/libfiemap_writer/fiemap_writer_test.cpp +87 −9 Original line number Diff line number Diff line Loading @@ -33,8 +33,10 @@ #include <android-base/unique_fd.h> #include <gtest/gtest.h> #include <libdm/loop_control.h> #include <libfiemap_writer/fiemap_writer.h> #include <libfiemap_writer/split_fiemap_writer.h> #include "utility.h" using namespace std; using namespace std::string_literals; Loading @@ -59,6 +61,24 @@ class FiemapWriterTest : public ::testing::Test { std::string testfile; }; class SplitFiemapTest : public ::testing::Test { protected: void SetUp() override { const ::testing::TestInfo* tinfo = ::testing::UnitTest::GetInstance()->current_test_info(); testfile = gTestDir + "/"s + tinfo->name(); } void TearDown() override { std::string message; if (!SplitFiemap::RemoveSplitFiles(testfile, &message)) { cerr << "Could not remove all split files: " << message; } } // name of the file we use for testing std::string testfile; }; TEST_F(FiemapWriterTest, CreateImpossiblyLargeFile) { // Try creating a file of size ~100TB but aligned to // 512 byte to make sure block alignment tests don't Loading @@ -71,8 +91,7 @@ TEST_F(FiemapWriterTest, CreateImpossiblyLargeFile) { TEST_F(FiemapWriterTest, CreateUnalignedFile) { // Try creating a file of size 4097 bytes which is guaranteed // to be unaligned to all known block sizes. The creation must // fail. // to be unaligned to all known block sizes. FiemapUniquePtr fptr = FiemapWriter::Open(testfile, gBlockSize + 1); ASSERT_NE(fptr, nullptr); ASSERT_EQ(fptr->size(), gBlockSize * 2); Loading @@ -87,10 +106,7 @@ TEST_F(FiemapWriterTest, CheckFilePath) { } TEST_F(FiemapWriterTest, CheckProgress) { std::vector<uint64_t> expected{ 0, gBlockSize, }; std::vector<uint64_t> expected; size_t invocations = 0; auto callback = [&](uint64_t done, uint64_t total) -> bool { EXPECT_LT(invocations, expected.size()); Loading @@ -100,9 +116,22 @@ TEST_F(FiemapWriterTest, CheckProgress) { return true; }; uint32_t fs_type; { auto ptr = FiemapWriter::Open(testfile, gBlockSize, true); ASSERT_NE(ptr, nullptr); fs_type = ptr->fs_type(); } ASSERT_EQ(unlink(testfile.c_str()), 0); if (fs_type != MSDOS_SUPER_MAGIC) { expected.push_back(0); } expected.push_back(gBlockSize); auto ptr = FiemapWriter::Open(testfile, gBlockSize, true, std::move(callback)); EXPECT_NE(ptr, nullptr); EXPECT_EQ(invocations, 2); EXPECT_EQ(invocations, expected.size()); } TEST_F(FiemapWriterTest, CheckPinning) { Loading Loading @@ -159,6 +188,52 @@ TEST_F(FiemapWriterTest, FileDeletedOnError) { EXPECT_EQ(errno, ENOENT); } TEST_F(FiemapWriterTest, MaxBlockSize) { ASSERT_GT(DetermineMaximumFileSize(testfile), 0); } TEST_F(SplitFiemapTest, Create) { auto ptr = SplitFiemap::Create(testfile, 1024 * 768, 1024 * 32); ASSERT_NE(ptr, nullptr); auto extents = ptr->extents(); // Destroy the fiemap, closing file handles. This should not delete them. ptr = nullptr; std::vector<std::string> files; ASSERT_TRUE(SplitFiemap::GetSplitFileList(testfile, &files)); for (const auto& path : files) { EXPECT_EQ(access(path.c_str(), F_OK), 0); } ASSERT_GE(extents.size(), files.size()); } TEST_F(SplitFiemapTest, Open) { { auto ptr = SplitFiemap::Create(testfile, 1024 * 768, 1024 * 32); ASSERT_NE(ptr, nullptr); } auto ptr = SplitFiemap::Open(testfile); ASSERT_NE(ptr, nullptr); auto extents = ptr->extents(); ASSERT_GE(extents.size(), 24); } TEST_F(SplitFiemapTest, DeleteOnFail) { auto ptr = SplitFiemap::Create(testfile, 1024 * 1024 * 10, 1); ASSERT_EQ(ptr, nullptr); std::string first_file = testfile + ".0001"; ASSERT_NE(access(first_file.c_str(), F_OK), 0); ASSERT_EQ(errno, ENOENT); ASSERT_NE(access(testfile.c_str(), F_OK), 0); ASSERT_EQ(errno, ENOENT); } class VerifyBlockWritesExt4 : public ::testing::Test { // 2GB Filesystem and 4k block size by default static constexpr uint64_t block_size = 4096; Loading Loading @@ -273,7 +348,10 @@ int main(int argc, char** argv) { cerr << "unable to create tempdir on " << argv[1] << "\n"; exit(EXIT_FAILURE); } gTestDir = tempdir; if (!android::base::Realpath(tempdir, &gTestDir)) { cerr << "unable to find realpath for " << tempdir; exit(EXIT_FAILURE); } if (argc > 2) { testfile_size = strtoull(argv[2], NULL, 0); Loading