From 0fa371076acfc89f6f5de999e92af4d0eccb790a Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 15 May 2023 16:43:53 -0700 Subject: [PATCH] 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 --- fs_mgr/libfiemap/fiemap_writer.cpp | 31 +++++++++++++++++-- .../include/libfiemap/fiemap_status.h | 3 +- 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/fs_mgr/libfiemap/fiemap_writer.cpp b/fs_mgr/libfiemap/fiemap_writer.cpp index 275388ed9..06e210eca 100644 --- a/fs_mgr/libfiemap/fiemap_writer.cpp +++ b/fs_mgr/libfiemap/fiemap_writer.cpp @@ -458,9 +458,34 @@ static FiemapStatus AllocateFile(int file_fd, const std::string& file_path, uint 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 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 d7b2cf18e..1365ba4be 100644 --- a/fs_mgr/libfiemap/include/libfiemap/fiemap_status.h +++ b/fs_mgr/libfiemap/include/libfiemap/fiemap_status.h @@ -56,8 +56,7 @@ class FiemapStatus { // 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_;