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 |