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
This commit is contained in:
Kelvin Zhang 2022-11-08 10:01:25 -08:00
parent b190f3cbe1
commit 149fa74db5
2 changed files with 22 additions and 2 deletions

View File

@ -17,6 +17,7 @@
#include <errno.h>
#include <time.h>
#include <filesystem>
#include <iomanip>
#include <sstream>
@ -152,6 +153,24 @@ AutoUnmountDevice::~AutoUnmountDevice() {
}
}
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 @@ bool WriteStringToFileAtomic(const std::string& content, const std::string& path
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");

View File

@ -117,6 +117,7 @@ Return InitializeKernelCow(const std::string& device);
// 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 {};