|
@@ -133,6 +133,16 @@ ErrorOr<void> BlockBasedFileSystem::write_block(BlockIndex index, const UserOrKe
|
|
VERIFY(offset + count <= block_size());
|
|
VERIFY(offset + count <= block_size());
|
|
dbgln_if(BBFS_DEBUG, "BlockBasedFileSystem::write_block {}, size={}", index, count);
|
|
dbgln_if(BBFS_DEBUG, "BlockBasedFileSystem::write_block {}, size={}", index, count);
|
|
|
|
|
|
|
|
+ // NOTE: We copy the `data` to write into a local buffer before taking the cache lock.
|
|
|
|
+ // This makes sure any page faults caused by accessing the data will occur before
|
|
|
|
+ // we tie down the cache.
|
|
|
|
+ auto buffered_data_or_error = ByteBuffer::create_uninitialized(count);
|
|
|
|
+ if (!buffered_data_or_error.has_value())
|
|
|
|
+ return ENOMEM;
|
|
|
|
+ auto buffered_data = buffered_data_or_error.release_value();
|
|
|
|
+
|
|
|
|
+ TRY(data.read(buffered_data.bytes()));
|
|
|
|
+
|
|
return m_cache.with_exclusive([&](auto& cache) -> ErrorOr<void> {
|
|
return m_cache.with_exclusive([&](auto& cache) -> ErrorOr<void> {
|
|
if (!allow_cache) {
|
|
if (!allow_cache) {
|
|
flush_specific_block_if_needed(index);
|
|
flush_specific_block_if_needed(index);
|
|
@@ -147,7 +157,7 @@ ErrorOr<void> BlockBasedFileSystem::write_block(BlockIndex index, const UserOrKe
|
|
// Fill the cache first.
|
|
// Fill the cache first.
|
|
TRY(read_block(index, nullptr, block_size()));
|
|
TRY(read_block(index, nullptr, block_size()));
|
|
}
|
|
}
|
|
- TRY(data.read(entry.data + offset, count));
|
|
|
|
|
|
+ memcpy(entry.data + offset, buffered_data.data(), count);
|
|
|
|
|
|
cache->mark_dirty(entry);
|
|
cache->mark_dirty(entry);
|
|
entry.has_data = true;
|
|
entry.has_data = true;
|