summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author David Srbecky <dsrbecky@google.com> 2024-11-15 16:25:20 +0000
committer Steven Moreland <smoreland@google.com> 2025-01-30 12:45:17 -0800
commit7a0ce584dfa185d29de6671930a5ee1fee902609 (patch)
tree45bedeb413d0694e4612cd0344c0154309814f42
parentd8261f0d75a338c4b74bac006ae7a884f88b1e02 (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.cc21
-rw-r--r--libartbase/base/unix_file/fd_file.h3
-rw-r--r--libelffile/stream/file_output_stream.cc50
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));
}