Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2973)

Unified Diff: base/files/memory_mapped_file_posix.cc

Issue 2860943005: Ensure that memory-maped files are fully realized. (Closed)
Patch Set: use existing_byte for write Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: base/files/memory_mapped_file_posix.cc
diff --git a/base/files/memory_mapped_file_posix.cc b/base/files/memory_mapped_file_posix.cc
index 90ba6f49c1573f6fb4fb1f56bc33f35b36febb06..55b754d83a01723e8e7aa76475bd90d299bca266 100644
--- a/base/files/memory_mapped_file_posix.cc
+++ b/base/files/memory_mapped_file_posix.cc
@@ -4,6 +4,7 @@
#include "base/files/memory_mapped_file.h"
+#include <fcntl.h>
#include <stddef.h>
#include <stdint.h>
#include <sys/mman.h>
@@ -14,6 +15,10 @@
#include "base/threading/thread_restrictions.h"
#include "build/build_config.h"
+#if defined(OS_ANDROID)
+#include <android/api-level.h>
+#endif
+
namespace base {
MemoryMappedFile::MemoryMappedFile() : data_(NULL), length_(0) {
@@ -71,22 +76,75 @@ bool MemoryMappedFile::MapFileRegionToMemory(
case READ_ONLY:
flags |= PROT_READ;
break;
+
case READ_WRITE:
flags |= PROT_READ | PROT_WRITE;
break;
+
case READ_WRITE_EXTEND:
+ flags |= PROT_READ | PROT_WRITE;
+
// POSIX won't auto-extend the file when it is written so it must first
// be explicitly extended to the maximum size. Zeros will fill the new
// space.
- auto file_len = file_.GetLength();
- if (file_len < 0) {
+ const int64_t original_file_len = file_.GetLength();
+ if (original_file_len < 0) {
DPLOG(ERROR) << "fstat " << file_.GetPlatformFile();
return false;
}
- file_.SetLength(std::max(file_len, region.offset + region.size));
- flags |= PROT_READ | PROT_WRITE;
+
+ // Increase the actual length of the file, if necessary. This can fail if
+ // the disk is full and the OS doesn't support sparse files.
+ if (!file_.SetLength(
+ std::max(original_file_len, region.offset + region.size))) {
+ DPLOG(ERROR) << "ftruncate " << file_.GetPlatformFile();
+ return false;
+ }
+
+ // Realize the extent of the file so that it can't fail (and crash) later
+ // when trying to write to a memory page that can't be created. This can
+ // fail if the disk is full and the file is sparse.
+ //
+ // Only Android API>=21 supports the fallocate call. Older versions need
+ // to manually extend the file by writing zeros at block intervals.
+ //
+ // Mac OSX doesn't support this call but the primary filesystem doesn't
+ // support sparse files so is unneeded.
+ bool do_manual_extension = false;
+
+#if defined(OS_ANDROID) && __ANDROID_API__ < 21
+ do_manual_extension = true;
+#elif !defined(OS_MACOSX)
+ if (posix_fallocate(file_.GetPlatformFile(), region.offset,
+ region.size) != 0) {
+ DPLOG(ERROR) << "posix_fallocate " << file_.GetPlatformFile();
+ // This can fail because the filesystem doesn't support it so don't
+ // give up just yet. Try the manual method below.
+ do_manual_extension = true;
+ }
+#endif
+
+ // Manually realize the entire file by writing bytes to it at intervals.
+ if (do_manual_extension) {
+ int64_t block_size = 1024; // Start with something safe.
+ struct stat statbuf;
+ if (fstat(file_.GetPlatformFile(), &statbuf) == 0)
+ block_size = statbuf.st_blksize;
+ const off_t map_end = map_start + static_cast<off_t>(map_size);
+ for (off_t i = map_start; i < map_end; i += block_size) {
+ char existing_byte;
+ if (pread(file_.GetPlatformFile(), &existing_byte, 1, i) != 1)
+ return false; // Can't read? Not viable.
+ if (existing_byte != 0)
+ continue; // Block has data so must already exist.
+ if (pwrite(file_.GetPlatformFile(), &existing_byte, 1, i) != 1)
+ return false; // Can't write? Not viable.
+ }
+ }
+
break;
}
+
data_ = static_cast<uint8_t*>(mmap(NULL, map_size, flags, MAP_SHARED,
file_.GetPlatformFile(), map_start));
if (data_ == MAP_FAILED) {
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698