summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Yurii Zubrytskyi <zyy@google.com> 2021-03-17 13:18:30 -0700
committer Yurii Zubrytskyi <zyy@google.com> 2021-03-17 13:21:10 -0700
commit65fc38a029e36687adf3a2f25355315bff8855e7 (patch)
tree35af51b4fbe184f24accf33c9e4ca65b281092d1
parentd96c8193e28c4f3a8e6068fdb7ebe4b9cd5d0faa (diff)
[incfs] Preallocate space for IncFS files
Use the new libincfs APIs to preallocate space for all files created via the public makeFile() API. This way we ensure the device won't run out of space much later Bug: 182185202 Test: atest libincfs-test PackageManagerShellCommandTest \ PackageManagerShellCommandIncrementalTest \ IncrementalServiceTest Change-Id: I70af97949b29ff5db63201b0e3487fe026e23160
-rw-r--r--services/incremental/IncrementalService.cpp54
-rw-r--r--services/incremental/ServiceWrappers.cpp4
-rw-r--r--services/incremental/ServiceWrappers.h2
-rw-r--r--services/incremental/test/IncrementalServiceTest.cpp7
4 files changed, 55 insertions, 12 deletions
diff --git a/services/incremental/IncrementalService.cpp b/services/incremental/IncrementalService.cpp
index e3fbeddc3a5f..db70d44d37f6 100644
--- a/services/incremental/IncrementalService.cpp
+++ b/services/incremental/IncrementalService.cpp
@@ -96,6 +96,10 @@ static const Constants& constants() {
return c;
}
+static bool isPageAligned(IncFsSize s) {
+ return (s & (Constants::blockSize - 1)) == 0;
+}
+
template <base::LogSeverity level = base::ERROR>
bool mkdirOrLog(std::string_view name, int mode = 0770, bool allowExisting = true) {
auto cstr = path::c_str(name);
@@ -1001,25 +1005,53 @@ std::string IncrementalService::normalizePathToStorage(const IncFsMount& ifs, St
int IncrementalService::makeFile(StorageId storage, std::string_view path, int mode, FileId id,
incfs::NewFileParams params, std::span<const uint8_t> data) {
- if (auto ifs = getIfs(storage)) {
- std::string normPath = normalizePathToStorage(*ifs, storage, path);
- if (normPath.empty()) {
- LOG(ERROR) << "Internal error: storageId " << storage
- << " failed to normalize: " << path;
+ const auto ifs = getIfs(storage);
+ if (!ifs) {
+ return -EINVAL;
+ }
+ if (data.size() > params.size) {
+ LOG(ERROR) << "Bad data size - bigger than file size";
+ return -EINVAL;
+ }
+ if (!data.empty() && data.size() != params.size) {
+ // Writing a page is an irreversible operation, and it can't be updated with additional
+ // data later. Check that the last written page is complete, or we may break the file.
+ if (!isPageAligned(data.size())) {
+ LOG(ERROR) << "Bad data size - tried to write half a page?";
return -EINVAL;
}
- if (auto err = mIncFs->makeFile(ifs->control, normPath, mode, id, params); err) {
- LOG(ERROR) << "Internal error: storageId " << storage << " failed to makeFile: " << err;
- return err;
+ }
+ const std::string normPath = normalizePathToStorage(*ifs, storage, path);
+ if (normPath.empty()) {
+ LOG(ERROR) << "Internal error: storageId " << storage << " failed to normalize: " << path;
+ return -EINVAL;
+ }
+ if (auto err = mIncFs->makeFile(ifs->control, normPath, mode, id, params); err) {
+ LOG(ERROR) << "Internal error: storageId " << storage << " failed to makeFile: " << err;
+ return err;
+ }
+ if (params.size > 0) {
+ // Only v2+ incfs supports automatically trimming file over-reserved sizes
+ if (mIncFs->features() & incfs::Features::v2) {
+ if (auto err = mIncFs->reserveSpace(ifs->control, normPath, params.size)) {
+ if (err != -EOPNOTSUPP) {
+ LOG(ERROR) << "Failed to reserve space for a new file: " << err;
+ (void)mIncFs->unlink(ifs->control, normPath);
+ return err;
+ } else {
+ LOG(WARNING) << "Reserving space for backing file isn't supported, "
+ "may run out of disk later";
+ }
+ }
}
if (!data.empty()) {
if (auto err = setFileContent(ifs, id, path, data); err) {
+ (void)mIncFs->unlink(ifs->control, normPath);
return err;
}
}
- return 0;
}
- return -EINVAL;
+ return 0;
}
int IncrementalService::makeDir(StorageId storageId, std::string_view path, int mode) {
@@ -1708,7 +1740,7 @@ bool IncrementalService::configureNativeBinaries(StorageId storage, std::string_
}
const auto entryUncompressed = entry.method == kCompressStored;
- const auto entryPageAligned = (entry.offset & (constants().blockSize - 1)) == 0;
+ const auto entryPageAligned = isPageAligned(entry.offset);
if (!extractNativeLibs) {
// ensure the file is properly aligned and unpacked
diff --git a/services/incremental/ServiceWrappers.cpp b/services/incremental/ServiceWrappers.cpp
index 80f409ff1c61..2a061226b713 100644
--- a/services/incremental/ServiceWrappers.cpp
+++ b/services/incremental/ServiceWrappers.cpp
@@ -209,6 +209,10 @@ public:
ErrorCode writeBlocks(std::span<const incfs::DataBlock> blocks) const final {
return incfs::writeBlocks({blocks.data(), size_t(blocks.size())});
}
+ ErrorCode reserveSpace(const Control& control, std::string_view path,
+ IncFsSize size) const final {
+ return incfs::reserveSpace(control, path, size);
+ }
WaitResult waitForPendingReads(const Control& control, std::chrono::milliseconds timeout,
std::vector<incfs::ReadInfo>* pendingReadsBuffer) const final {
return incfs::waitForPendingReads(control, timeout, pendingReadsBuffer);
diff --git a/services/incremental/ServiceWrappers.h b/services/incremental/ServiceWrappers.h
index d113f992de71..231b76ff1701 100644
--- a/services/incremental/ServiceWrappers.h
+++ b/services/incremental/ServiceWrappers.h
@@ -107,6 +107,8 @@ public:
virtual ErrorCode unlink(const Control& control, std::string_view path) const = 0;
virtual UniqueFd openForSpecialOps(const Control& control, FileId id) const = 0;
virtual ErrorCode writeBlocks(std::span<const incfs::DataBlock> blocks) const = 0;
+ virtual ErrorCode reserveSpace(const Control& control, std::string_view path,
+ IncFsSize size) const = 0;
virtual WaitResult waitForPendingReads(
const Control& control, std::chrono::milliseconds timeout,
std::vector<incfs::ReadInfo>* pendingReadsBuffer) const = 0;
diff --git a/services/incremental/test/IncrementalServiceTest.cpp b/services/incremental/test/IncrementalServiceTest.cpp
index bf798273a8a9..45b796bf4704 100644
--- a/services/incremental/test/IncrementalServiceTest.cpp
+++ b/services/incremental/test/IncrementalServiceTest.cpp
@@ -372,6 +372,8 @@ public:
MOCK_CONST_METHOD2(unlink, ErrorCode(const Control& control, std::string_view path));
MOCK_CONST_METHOD2(openForSpecialOps, UniqueFd(const Control& control, FileId id));
MOCK_CONST_METHOD1(writeBlocks, ErrorCode(std::span<const DataBlock> blocks));
+ MOCK_CONST_METHOD3(reserveSpace,
+ ErrorCode(const Control& control, std::string_view path, IncFsSize size));
MOCK_CONST_METHOD3(waitForPendingReads,
WaitResult(const Control& control, std::chrono::milliseconds timeout,
std::vector<incfs::ReadInfo>* pendingReadsBuffer));
@@ -379,7 +381,10 @@ public:
ErrorCode(const Control& control,
const std::vector<PerUidReadTimeouts>& perUidReadTimeouts));
- MockIncFs() { ON_CALL(*this, listExistingMounts(_)).WillByDefault(Return()); }
+ MockIncFs() {
+ ON_CALL(*this, listExistingMounts(_)).WillByDefault(Return());
+ ON_CALL(*this, reserveSpace(_, _, _)).WillByDefault(Return(0));
+ }
void makeFileFails() { ON_CALL(*this, makeFile(_, _, _, _, _)).WillByDefault(Return(-1)); }
void makeFileSuccess() { ON_CALL(*this, makeFile(_, _, _, _, _)).WillByDefault(Return(0)); }