libfiemap: Handle EAGAIN in fallocate().
When we changed our ENOSPC tests, it exposed a path in F2FS were
fallocate can return EAGAIN. This is expected if F2FS attempts GC to
acquire more chunks, and it can leave the file in a partially allocated
state.
As a fix, keep attempting fallocate() as long as (1) it returns EAGAIN,
and (2) the allocated size keeps growing. If (2) fails we return ENOSPC.
Bug: N/A
Test: treehugger
Change-Id: I5f867b5a200b9260e486985f203f9872a949b3f9
diff --git a/fs_mgr/libfiemap/fiemap_writer.cpp b/fs_mgr/libfiemap/fiemap_writer.cpp
index 275388e..06e210e 100644
--- a/fs_mgr/libfiemap/fiemap_writer.cpp
+++ b/fs_mgr/libfiemap/fiemap_writer.cpp
@@ -458,9 +458,34 @@
return FiemapStatus::Error();
}
- if (fallocate(file_fd, 0, 0, file_size)) {
- PLOG(ERROR) << "Failed to allocate space for file: " << file_path << " size: " << file_size;
- return FiemapStatus::FromErrno(errno);
+ // F2FS can return EAGAIN and partially fallocate. Keep trying to fallocate,
+ // and if we don't make forward progress, return ENOSPC.
+ std::optional<off_t> prev_size;
+ while (true) {
+ if (fallocate(file_fd, 0, 0, file_size) == 0) {
+ break;
+ }
+ if (errno != EAGAIN) {
+ PLOG(ERROR) << "Failed to allocate space for file: " << file_path
+ << " size: " << file_size;
+ return FiemapStatus::FromErrno(errno);
+ }
+
+ struct stat s;
+ if (fstat(file_fd, &s) < 0) {
+ PLOG(ERROR) << "Failed to fstat after fallocate failure: " << file_path;
+ return FiemapStatus::FromErrno(errno);
+ }
+ if (!prev_size) {
+ prev_size = {s.st_size};
+ continue;
+ }
+ if (*prev_size >= s.st_size) {
+ LOG(ERROR) << "Fallocate retry failed, got " << s.st_size << ", asked for "
+ << file_size;
+ return FiemapStatus(FiemapStatus::ErrorCode::NO_SPACE);
+ }
+ LOG(INFO) << "Retrying fallocate, got " << s.st_size << ", asked for " << file_size;
}
if (need_explicit_writes) {
diff --git a/fs_mgr/libfiemap/include/libfiemap/fiemap_status.h b/fs_mgr/libfiemap/include/libfiemap/fiemap_status.h
index d7b2cf1..1365ba4 100644
--- a/fs_mgr/libfiemap/include/libfiemap/fiemap_status.h
+++ b/fs_mgr/libfiemap/include/libfiemap/fiemap_status.h
@@ -56,8 +56,7 @@
// For logging and debugging only.
std::string string() const;
- protected:
- FiemapStatus(ErrorCode code) : error_code_(code) {}
+ explicit FiemapStatus(ErrorCode code) : error_code_(code) {}
private:
ErrorCode error_code_;