Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "base/files/memory_mapped_file.h" | 5 #include "base/files/memory_mapped_file.h" |
| 6 | 6 |
| 7 #include <fcntl.h> | 7 #include <fcntl.h> |
| 8 #include <stddef.h> | 8 #include <stddef.h> |
| 9 #include <stdint.h> | 9 #include <stdint.h> |
| 10 #include <sys/mman.h> | 10 #include <sys/mman.h> |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 77 flags |= PROT_READ; | 77 flags |= PROT_READ; |
| 78 break; | 78 break; |
| 79 | 79 |
| 80 case READ_WRITE: | 80 case READ_WRITE: |
| 81 flags |= PROT_READ | PROT_WRITE; | 81 flags |= PROT_READ | PROT_WRITE; |
| 82 break; | 82 break; |
| 83 | 83 |
| 84 case READ_WRITE_EXTEND: | 84 case READ_WRITE_EXTEND: |
| 85 flags |= PROT_READ | PROT_WRITE; | 85 flags |= PROT_READ | PROT_WRITE; |
| 86 | 86 |
| 87 const int64_t new_file_len = region.offset + region.size; | |
| 88 | |
| 87 // POSIX won't auto-extend the file when it is written so it must first | 89 // POSIX won't auto-extend the file when it is written so it must first |
| 88 // be explicitly extended to the maximum size. Zeros will fill the new | 90 // be explicitly extended to the maximum size. Zeros will fill the new |
| 89 // space. | 91 // space. It is assumed that the existing file is fully realized as |
| 92 // otherwise the entire file would have to be read and possibly written. | |
| 90 const int64_t original_file_len = file_.GetLength(); | 93 const int64_t original_file_len = file_.GetLength(); |
| 91 if (original_file_len < 0) { | 94 if (original_file_len < 0) { |
| 92 DPLOG(ERROR) << "fstat " << file_.GetPlatformFile(); | 95 DPLOG(ERROR) << "fstat " << file_.GetPlatformFile(); |
| 93 return false; | 96 return false; |
| 94 } | 97 } |
| 95 | 98 |
| 96 // Increase the actual length of the file, if necessary. This can fail if | 99 // Increase the actual length of the file, if necessary. This can fail if |
| 97 // the disk is full and the OS doesn't support sparse files. | 100 // the disk is full and the OS doesn't support sparse files. |
| 98 if (!file_.SetLength( | 101 if (!file_.SetLength(std::max(original_file_len, new_file_len))) { |
| 99 std::max(original_file_len, region.offset + region.size))) { | |
| 100 DPLOG(ERROR) << "ftruncate " << file_.GetPlatformFile(); | 102 DPLOG(ERROR) << "ftruncate " << file_.GetPlatformFile(); |
| 101 return false; | 103 return false; |
| 102 } | 104 } |
| 103 | 105 |
| 104 // Realize the extent of the file so that it can't fail (and crash) later | 106 // Realize the extent of the file so that it can't fail (and crash) later |
| 105 // when trying to write to a memory page that can't be created. This can | 107 // when trying to write to a memory page that can't be created. This can |
| 106 // fail if the disk is full and the file is sparse. | 108 // fail if the disk is full and the file is sparse. |
| 107 // | 109 // |
| 108 // Only Android API>=21 supports the fallocate call. Older versions need | 110 // Only Android API>=21 supports the fallocate call. Older versions need |
| 109 // to manually extend the file by writing zeros at block intervals. | 111 // to manually extend the file by writing zeros at block intervals. |
| 110 // | 112 // |
| 111 // Mac OSX doesn't support this call but the primary filesystem doesn't | 113 // Mac OSX doesn't support this call but the primary filesystem doesn't |
| 112 // support sparse files so is unneeded. | 114 // support sparse files so is unneeded. |
| 113 bool do_manual_extension = false; | 115 bool do_manual_extension = false; |
| 114 | 116 |
| 115 #if defined(OS_ANDROID) && __ANDROID_API__ < 21 | 117 #if defined(OS_ANDROID) && __ANDROID_API__ < 21 |
| 116 do_manual_extension = true; | 118 do_manual_extension = true; |
| 117 #elif !defined(OS_MACOSX) | 119 #elif !defined(OS_MACOSX) |
| 118 if (posix_fallocate(file_.GetPlatformFile(), region.offset, | 120 if (posix_fallocate(file_.GetPlatformFile(), region.offset, |
| 119 region.size) != 0) { | 121 region.size) != 0) { |
| 120 DPLOG(ERROR) << "posix_fallocate " << file_.GetPlatformFile(); | 122 DPLOG(ERROR) << "posix_fallocate " << file_.GetPlatformFile(); |
| 121 // This can fail because the filesystem doesn't support it so don't | 123 // This can fail because the filesystem doesn't support it so don't |
| 122 // give up just yet. Try the manual method below. | 124 // give up just yet. Try the manual method below. |
| 123 do_manual_extension = true; | 125 do_manual_extension = true; |
| 124 } | 126 } |
| 125 #endif | 127 #endif |
| 126 | 128 |
| 127 // Manually realize the entire file by writing bytes to it at intervals. | 129 // Manually realize the extended file by writing bytes to it at intervals. |
| 128 if (do_manual_extension) { | 130 if (do_manual_extension) { |
| 129 int64_t block_size = 1024; // Start with something safe. | 131 int64_t block_size = 512; // Start with something safe. |
| 130 struct stat statbuf; | 132 struct stat statbuf; |
| 131 if (fstat(file_.GetPlatformFile(), &statbuf) == 0) | 133 if (fstat(file_.GetPlatformFile(), &statbuf) == 0 && |
| 134 statbuf.st_blksize > 0) { | |
| 132 block_size = statbuf.st_blksize; | 135 block_size = statbuf.st_blksize; |
| 133 #if defined(OS_FUCHSIA) | 136 } |
| 134 // TODO(fuchsia): Fuchsia stat() currently returns 0 for st_blksize, | 137 |
| 135 // which hangs the loop below. Remove this after the next SDK update. | 138 // Write starting at the next block boundary after the old file length. |
| 136 // https://crbug.com/706592 and MG-815. | 139 const int64_t extension_start = |
| 137 if (block_size == 0) | 140 (original_file_len + block_size - 1) & ~(block_size - 1); |
| 138 block_size = 512; | 141 for (int64_t i = extension_start; i < new_file_len; i += block_size) { |
| 139 #endif // defined(OS_FUCHSIA) | |
| 140 const off_t map_end = map_start + static_cast<off_t>(map_size); | |
| 141 for (off_t i = map_start; i < map_end; i += block_size) { | |
| 142 char existing_byte; | 142 char existing_byte; |
| 143 if (pread(file_.GetPlatformFile(), &existing_byte, 1, i) != 1) | 143 if (pread(file_.GetPlatformFile(), &existing_byte, 1, i) != 1) |
| 144 return false; // Can't read? Not viable. | 144 return false; // Can't read? Not viable. |
| 145 if (existing_byte != 0) | 145 if (existing_byte != 0) |
| 146 continue; // Block has data so must already exist. | 146 continue; // Block has data so must already exist. |
| 147 if (pwrite(file_.GetPlatformFile(), &existing_byte, 1, i) != 1) | 147 if (pwrite(file_.GetPlatformFile(), &existing_byte, 1, i) != 1) |
| 148 return false; // Can't write? Not viable. | 148 return false; // Can't write? Not viable. |
|
Mark Mentovai
2017/06/15 15:31:23
If we hit this, does something cause the file to b
bcwhite
2017/06/15 15:38:19
With regard to persistent histograms, the unused f
| |
| 149 } | 149 } |
| 150 } | 150 } |
| 151 | 151 |
| 152 break; | 152 break; |
| 153 } | 153 } |
| 154 | 154 |
| 155 data_ = static_cast<uint8_t*>(mmap(NULL, map_size, flags, MAP_SHARED, | 155 data_ = static_cast<uint8_t*>(mmap(NULL, map_size, flags, MAP_SHARED, |
| 156 file_.GetPlatformFile(), map_start)); | 156 file_.GetPlatformFile(), map_start)); |
| 157 if (data_ == MAP_FAILED) { | 157 if (data_ == MAP_FAILED) { |
| 158 DPLOG(ERROR) << "mmap " << file_.GetPlatformFile(); | 158 DPLOG(ERROR) << "mmap " << file_.GetPlatformFile(); |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 169 | 169 |
| 170 if (data_ != NULL) | 170 if (data_ != NULL) |
| 171 munmap(data_, length_); | 171 munmap(data_, length_); |
| 172 file_.Close(); | 172 file_.Close(); |
| 173 | 173 |
| 174 data_ = NULL; | 174 data_ = NULL; |
| 175 length_ = 0; | 175 length_ = 0; |
| 176 } | 176 } |
| 177 | 177 |
| 178 } // namespace base | 178 } // namespace base |
| OLD | NEW |