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:
parent
b190f3cbe1
commit
149fa74db5
|
@ -17,6 +17,7 @@
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <sstream>
|
#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) {
|
bool WriteStringToFileAtomic(const std::string& content, const std::string& path) {
|
||||||
const std::string tmp_path = path + ".tmp";
|
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;
|
PLOG(ERROR) << "rename failed from " << tmp_path << " to " << path;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return FsyncDirectory(std::filesystem::path(path).parent_path().c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::ostream& operator<<(std::ostream& os, const Now&) {
|
std::ostream& operator<<(std::ostream& os, const Now&) {
|
||||||
struct tm now;
|
struct tm now {};
|
||||||
time_t t = time(nullptr);
|
time_t t = time(nullptr);
|
||||||
localtime_r(&t, &now);
|
localtime_r(&t, &now);
|
||||||
return os << std::put_time(&now, "%Y%m%d-%H%M%S");
|
return os << std::put_time(&now, "%Y%m%d-%H%M%S");
|
||||||
|
|
|
@ -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
|
// 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.
|
// 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 WriteStringToFileAtomic(const std::string& content, const std::string& path);
|
||||||
|
bool FsyncDirectory(const char* dirname);
|
||||||
|
|
||||||
// Writes current time to a given stream.
|
// Writes current time to a given stream.
|
||||||
struct Now {};
|
struct Now {};
|
||||||
|
|
Loading…
Reference in New Issue