| 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) { | 
|  |