diff options
author | 2024-11-15 16:25:20 +0000 | |
---|---|---|
committer | 2025-01-30 12:45:17 -0800 | |
commit | 7a0ce584dfa185d29de6671930a5ee1fee902609 (patch) | |
tree | 45bedeb413d0694e4612cd0344c0154309814f42 | |
parent | d8261f0d75a338c4b74bac006ae7a884f88b1e02 (diff) |
Add option to write zeros instead of sparse.
Scoped to affected devices.
Test: test.py -r --host (with option on unconditionally)
Bug: 376814207
Bug: 387369198
Bug: 378792349
Change-Id: Ie0ab2d901540ae055fbe2c77179e4994458f6b9a
-rw-r--r-- | libartbase/base/unix_file/fd_file.cc | 21 | ||||
-rw-r--r-- | libartbase/base/unix_file/fd_file.h | 3 | ||||
-rw-r--r-- | libelffile/stream/file_output_stream.cc | 50 |
3 files changed, 73 insertions, 1 deletions
diff --git a/libartbase/base/unix_file/fd_file.cc b/libartbase/base/unix_file/fd_file.cc index 1387bfe9b8..2bdeb0cf52 100644 --- a/libartbase/base/unix_file/fd_file.cc +++ b/libartbase/base/unix_file/fd_file.cc @@ -24,6 +24,7 @@ #if defined(__BIONIC__) #include <android/fdsan.h> +#include <android/api-level.h> #endif #if defined(_WIN32) @@ -35,6 +36,7 @@ #include <android-base/file.h> #include <android-base/logging.h> +#include <android-base/properties.h> // Includes needed for FdFile::Copy(). #include "base/globals.h" @@ -49,6 +51,23 @@ namespace unix_file { +// f2fs decompress issue. +static bool b376814207() { +#ifdef __BIONIC__ + if (android_get_device_api_level() >= 35) { + return false; + } +#endif + std::string property = android::base::GetProperty("ro.product.build.fingerprint", ""); + return property.starts_with("samsung"); +} + +// Used to work around kernel bugs. +bool AllowSparseFiles() { + static bool allow = !b376814207(); + return allow; +} + #if defined(_WIN32) // RAII wrapper for an event object to allow asynchronous I/O to correctly signal completion. class ScopedEvent { @@ -534,7 +553,7 @@ bool FdFile::SparseWrite(const uint8_t* data, size_t size, const std::vector<uint8_t>& zeroes) { DCHECK_GE(zeroes.size(), size); - if (memcmp(zeroes.data(), data, size) == 0) { + if (memcmp(zeroes.data(), data, size) == 0 && AllowSparseFiles()) { // These bytes are all zeroes, skip them by moving the file offset via lseek SEEK_CUR (available // since linux kernel 3.1). if (TEMP_FAILURE_RETRY(lseek(Fd(), size, SEEK_CUR)) < 0) { diff --git a/libartbase/base/unix_file/fd_file.h b/libartbase/base/unix_file/fd_file.h index a46ef81586..035518ab8c 100644 --- a/libartbase/base/unix_file/fd_file.h +++ b/libartbase/base/unix_file/fd_file.h @@ -29,6 +29,9 @@ namespace unix_file { // If true, check whether Flush and Close are called before destruction. static constexpr bool kCheckSafeUsage = true; +// Used to work around kernel bugs. +bool AllowSparseFiles(); + // A RandomAccessFile implementation backed by a file descriptor. // // Not thread safe. diff --git a/libelffile/stream/file_output_stream.cc b/libelffile/stream/file_output_stream.cc index bbfbdfdca8..5afe366636 100644 --- a/libelffile/stream/file_output_stream.cc +++ b/libelffile/stream/file_output_stream.cc @@ -16,6 +16,8 @@ #include "file_output_stream.h" +#include <android-base/logging.h> +#include <sys/stat.h> #include <sys/types.h> #include <unistd.h> @@ -30,6 +32,54 @@ bool FileOutputStream::WriteFully(const void* buffer, size_t byte_count) { } off_t FileOutputStream::Seek(off_t offset, Whence whence) { + static const bool allow_sparse_files = unix_file::AllowSparseFiles(); + // If we are not allowed to generate sparse files, write zeros instead. + if (UNLIKELY(!allow_sparse_files)) { + // Check the current file size. + int fd = file_->Fd(); + struct stat sb; + if (fstat(fd, &sb) == -1) { + return -1; + } + off_t file_size = sb.st_size; + // Calculate new desired offset. + switch (whence) { + case kSeekSet: + break; + case kSeekCurrent: { + off_t curr_offset = lseek(fd, 0, SEEK_CUR); + if (curr_offset == -1) { + return -1; + } + offset += curr_offset; + whence = kSeekSet; + break; + } + case kSeekEnd: + offset += file_size; + whence = kSeekSet; + break; + default: + LOG(FATAL) << "Unsupported seek type: " << whence; + UNREACHABLE(); + } + // Write zeros if we are extending the file. + if (offset > file_size) { + off_t curr_offset = lseek(fd, 0, SEEK_END); + if (curr_offset == -1) { + return -1; + } + static const std::array<uint8_t, 1024> buffer{}; + while (curr_offset < offset) { + size_t size = std::min<size_t>(offset - curr_offset, buffer.size()); + ssize_t bytes_written = write(fd, buffer.data(), size); + if (bytes_written < 0) { + return -1; + } + curr_offset += bytes_written; + } + } + } return lseek(file_->Fd(), offset, static_cast<int>(whence)); } |