Fsync on directory after rename() call
rename() isn't necessarily atomic, call fsync() on the directory to
ensure that changes in fs structure hit the disk.
Test: th
Bug: 254211456
Change-Id: I2de842f03766a1108e0f54581738fb964989658a
diff --git a/fs_mgr/libsnapshot/utility.cpp b/fs_mgr/libsnapshot/utility.cpp
index cadd24d..a98bf0e 100644
--- a/fs_mgr/libsnapshot/utility.cpp
+++ b/fs_mgr/libsnapshot/utility.cpp
@@ -17,6 +17,7 @@
#include <errno.h>
#include <time.h>
+#include <filesystem>
#include <iomanip>
#include <sstream>
@@ -152,6 +153,24 @@
}
}
+bool FsyncDirectory(const char* dirname) {
+ android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(dirname, O_RDONLY | O_CLOEXEC)));
+ if (fd == -1) {
+ PLOG(ERROR) << "Failed to open " << dirname;
+ return false;
+ }
+ if (fsync(fd) == -1) {
+ if (errno == EROFS || errno == EINVAL) {
+ PLOG(WARNING) << "Skip fsync " << dirname
+ << " on a file system does not support synchronization";
+ } else {
+ PLOG(ERROR) << "Failed to fsync " << dirname;
+ return false;
+ }
+ }
+ return true;
+}
+
bool WriteStringToFileAtomic(const std::string& content, const std::string& path) {
const std::string tmp_path = path + ".tmp";
{
@@ -175,11 +194,11 @@
PLOG(ERROR) << "rename failed from " << tmp_path << " to " << path;
return false;
}
- return true;
+ return FsyncDirectory(std::filesystem::path(path).parent_path().c_str());
}
std::ostream& operator<<(std::ostream& os, const Now&) {
- struct tm now;
+ struct tm now {};
time_t t = time(nullptr);
localtime_r(&t, &now);
return os << std::put_time(&now, "%Y%m%d-%H%M%S");
diff --git a/fs_mgr/libsnapshot/utility.h b/fs_mgr/libsnapshot/utility.h
index eff6f10..8c4c7c6 100644
--- a/fs_mgr/libsnapshot/utility.h
+++ b/fs_mgr/libsnapshot/utility.h
@@ -117,6 +117,7 @@
// Note that rename() is an atomic operation. This function may not work properly if there
// is an open fd to |path|, because that fd has an old view of the file.
bool WriteStringToFileAtomic(const std::string& content, const std::string& path);
+bool FsyncDirectory(const char* dirname);
// Writes current time to a given stream.
struct Now {};