diff options
Diffstat (limited to 'Kernel/FileSystem')
25 files changed, 217 insertions, 155 deletions
diff --git a/Kernel/FileSystem/BlockBasedFileSystem.cpp b/Kernel/FileSystem/BlockBasedFileSystem.cpp index e5880e0897..2df34a58bb 100644 --- a/Kernel/FileSystem/BlockBasedFileSystem.cpp +++ b/Kernel/FileSystem/BlockBasedFileSystem.cpp @@ -119,7 +119,7 @@ BlockBasedFS::~BlockBasedFS() { } -bool BlockBasedFS::write_block(unsigned index, const u8* data, size_t count, size_t offset, bool allow_cache) +int BlockBasedFS::write_block(unsigned index, const UserOrKernelBuffer& data, size_t count, size_t offset, bool allow_cache) { ASSERT(m_logical_block_size); ASSERT(offset + count <= block_size()); @@ -133,9 +133,9 @@ bool BlockBasedFS::write_block(unsigned index, const u8* data, size_t count, siz file_description().seek(base_offset, SEEK_SET); auto nwritten = file_description().write(data, count); if (nwritten.is_error()) - return false; + return -EIO; // TODO: Return error code as-is, could be -EFAULT! ASSERT(nwritten.value() == count); - return true; + return 0; } auto& entry = cache().get(index); @@ -143,15 +143,16 @@ bool BlockBasedFS::write_block(unsigned index, const u8* data, size_t count, siz // Fill the cache first. read_block(index, nullptr, block_size()); } - memcpy(entry.data + offset, data, count); + if (!data.read(entry.data + offset, count)) + return -EFAULT; entry.is_dirty = true; entry.has_data = true; cache().set_dirty(true); - return true; + return 0; } -bool BlockBasedFS::raw_read(unsigned index, u8* buffer) +bool BlockBasedFS::raw_read(unsigned index, UserOrKernelBuffer& buffer) { u32 base_offset = static_cast<u32>(index) * static_cast<u32>(m_logical_block_size); file_description().seek(base_offset, SEEK_SET); @@ -160,7 +161,7 @@ bool BlockBasedFS::raw_read(unsigned index, u8* buffer) ASSERT(nread.value() == m_logical_block_size); return true; } -bool BlockBasedFS::raw_write(unsigned index, const u8* buffer) +bool BlockBasedFS::raw_write(unsigned index, const UserOrKernelBuffer& buffer) { u32 base_offset = static_cast<u32>(index) * static_cast<u32>(m_logical_block_size); file_description().seek(base_offset, SEEK_SET); @@ -170,37 +171,39 @@ bool BlockBasedFS::raw_write(unsigned index, const u8* buffer) return true; } -bool BlockBasedFS::raw_read_blocks(unsigned index, size_t count, u8* buffer) +bool BlockBasedFS::raw_read_blocks(unsigned index, size_t count, UserOrKernelBuffer& buffer) { + auto current = buffer; for (unsigned block = index; block < (index + count); block++) { - if (!raw_read(block, buffer)) + if (!raw_read(block, current)) return false; - buffer += logical_block_size(); + current = current.offset(logical_block_size()); } return true; } -bool BlockBasedFS::raw_write_blocks(unsigned index, size_t count, const u8* buffer) +bool BlockBasedFS::raw_write_blocks(unsigned index, size_t count, const UserOrKernelBuffer& buffer) { + auto current = buffer; for (unsigned block = index; block < (index + count); block++) { - if (!raw_write(block, buffer)) + if (!raw_write(block, current)) return false; - buffer += logical_block_size(); + current = current.offset(logical_block_size()); } return true; } -bool BlockBasedFS::write_blocks(unsigned index, unsigned count, const u8* data, bool allow_cache) +int BlockBasedFS::write_blocks(unsigned index, unsigned count, const UserOrKernelBuffer& data, bool allow_cache) { ASSERT(m_logical_block_size); #ifdef BBFS_DEBUG klog() << "BlockBasedFileSystem::write_blocks " << index << " x" << count; #endif for (unsigned i = 0; i < count; ++i) - write_block(index + i, data + i * block_size(), block_size(), 0, allow_cache); - return true; + write_block(index + i, data.offset(i * block_size()), block_size(), 0, allow_cache); + return 0; } -bool BlockBasedFS::read_block(unsigned index, u8* buffer, size_t count, size_t offset, bool allow_cache) const +int BlockBasedFS::read_block(unsigned index, UserOrKernelBuffer* buffer, size_t count, size_t offset, bool allow_cache) const { ASSERT(m_logical_block_size); ASSERT(offset + count <= block_size()); @@ -212,44 +215,45 @@ bool BlockBasedFS::read_block(unsigned index, u8* buffer, size_t count, size_t o const_cast<BlockBasedFS*>(this)->flush_specific_block_if_needed(index); u32 base_offset = static_cast<u32>(index) * static_cast<u32>(block_size()) + static_cast<u32>(offset); file_description().seek(base_offset, SEEK_SET); - auto nread = file_description().read(buffer, count); + auto nread = file_description().read(*buffer, count); if (nread.is_error()) - return false; + return -EIO; ASSERT(nread.value() == count); - return true; + return 0; } auto& entry = cache().get(index); if (!entry.has_data) { u32 base_offset = static_cast<u32>(index) * static_cast<u32>(block_size()); file_description().seek(base_offset, SEEK_SET); - auto nread = file_description().read(entry.data, block_size()); + auto entry_data_buffer = UserOrKernelBuffer::for_kernel_buffer(entry.data); + auto nread = file_description().read(entry_data_buffer, block_size()); if (nread.is_error()) - return false; + return -EIO; ASSERT(nread.value() == block_size()); entry.has_data = true; } - if (buffer) - memcpy(buffer, entry.data + offset, count); - return true; + if (buffer && !buffer->write(entry.data + offset, count)) + return -EFAULT; + return 0; } -bool BlockBasedFS::read_blocks(unsigned index, unsigned count, u8* buffer, bool allow_cache) const +int BlockBasedFS::read_blocks(unsigned index, unsigned count, UserOrKernelBuffer& buffer, bool allow_cache) const { ASSERT(m_logical_block_size); if (!count) return false; if (count == 1) - return read_block(index, buffer, block_size(), 0, allow_cache); - u8* out = buffer; - + return read_block(index, &buffer, block_size(), 0, allow_cache); + auto out = buffer; for (unsigned i = 0; i < count; ++i) { - if (!read_block(index + i, out, block_size(), 0, allow_cache)) - return false; - out += block_size(); + auto err = read_block(index + i, &out, block_size(), 0, allow_cache); + if (err < 0) + return err; + out = out.offset(block_size()); } - return true; + return 0; } void BlockBasedFS::flush_specific_block_if_needed(unsigned index) @@ -262,7 +266,8 @@ void BlockBasedFS::flush_specific_block_if_needed(unsigned index) u32 base_offset = static_cast<u32>(entry.block_index) * static_cast<u32>(block_size()); file_description().seek(base_offset, SEEK_SET); // FIXME: Should this error path be surfaced somehow? - (void)file_description().write(entry.data, block_size()); + auto entry_data_buffer = UserOrKernelBuffer::for_kernel_buffer(entry.data); + (void)file_description().write(entry_data_buffer, block_size()); entry.is_dirty = false; } }); @@ -280,7 +285,8 @@ void BlockBasedFS::flush_writes_impl() u32 base_offset = static_cast<u32>(entry.block_index) * static_cast<u32>(block_size()); file_description().seek(base_offset, SEEK_SET); // FIXME: Should this error path be surfaced somehow? - (void)file_description().write(entry.data, block_size()); + auto entry_data_buffer = UserOrKernelBuffer::for_kernel_buffer(entry.data); + (void)file_description().write(entry_data_buffer, block_size()); ++count; entry.is_dirty = false; }); diff --git a/Kernel/FileSystem/BlockBasedFileSystem.h b/Kernel/FileSystem/BlockBasedFileSystem.h index b9f7bdf601..fcf096aec3 100644 --- a/Kernel/FileSystem/BlockBasedFileSystem.h +++ b/Kernel/FileSystem/BlockBasedFileSystem.h @@ -42,17 +42,17 @@ public: protected: explicit BlockBasedFS(FileDescription&); - bool read_block(unsigned index, u8* buffer, size_t count, size_t offset = 0, bool allow_cache = true) const; - bool read_blocks(unsigned index, unsigned count, u8* buffer, bool allow_cache = true) const; + int read_block(unsigned index, UserOrKernelBuffer* buffer, size_t count, size_t offset = 0, bool allow_cache = true) const; + int read_blocks(unsigned index, unsigned count, UserOrKernelBuffer& buffer, bool allow_cache = true) const; - bool raw_read(unsigned index, u8* buffer); - bool raw_write(unsigned index, const u8* buffer); + bool raw_read(unsigned index, UserOrKernelBuffer& buffer); + bool raw_write(unsigned index, const UserOrKernelBuffer& buffer); - bool raw_read_blocks(unsigned index, size_t count, u8* buffer); - bool raw_write_blocks(unsigned index, size_t count, const u8* buffer); + bool raw_read_blocks(unsigned index, size_t count, UserOrKernelBuffer& buffer); + bool raw_write_blocks(unsigned index, size_t count, const UserOrKernelBuffer& buffer); - bool write_block(unsigned index, const u8* buffer, size_t count, size_t offset = 0, bool allow_cache = true); - bool write_blocks(unsigned index, unsigned count, const u8*, bool allow_cache = true); + int write_block(unsigned index, const UserOrKernelBuffer& buffer, size_t count, size_t offset = 0, bool allow_cache = true); + int write_blocks(unsigned index, unsigned count, const UserOrKernelBuffer&, bool allow_cache = true); size_t m_logical_block_size { 512 }; diff --git a/Kernel/FileSystem/DevPtsFS.cpp b/Kernel/FileSystem/DevPtsFS.cpp index 01b78c44c0..d05437591a 100644 --- a/Kernel/FileSystem/DevPtsFS.cpp +++ b/Kernel/FileSystem/DevPtsFS.cpp @@ -120,12 +120,12 @@ DevPtsFSInode::~DevPtsFSInode() { } -ssize_t DevPtsFSInode::read_bytes(off_t, ssize_t, u8*, FileDescription*) const +ssize_t DevPtsFSInode::read_bytes(off_t, ssize_t, UserOrKernelBuffer&, FileDescription*) const { ASSERT_NOT_REACHED(); } -ssize_t DevPtsFSInode::write_bytes(off_t, ssize_t, const u8*, FileDescription*) +ssize_t DevPtsFSInode::write_bytes(off_t, ssize_t, const UserOrKernelBuffer&, FileDescription*) { ASSERT_NOT_REACHED(); } diff --git a/Kernel/FileSystem/DevPtsFS.h b/Kernel/FileSystem/DevPtsFS.h index 3c302180fe..8ac7571136 100644 --- a/Kernel/FileSystem/DevPtsFS.h +++ b/Kernel/FileSystem/DevPtsFS.h @@ -67,12 +67,12 @@ private: DevPtsFSInode(DevPtsFS&, unsigned index, SlavePTY*); // ^Inode - virtual ssize_t read_bytes(off_t, ssize_t, u8* buffer, FileDescription*) const override; + virtual ssize_t read_bytes(off_t, ssize_t, UserOrKernelBuffer& buffer, FileDescription*) const override; virtual InodeMetadata metadata() const override; virtual KResult traverse_as_directory(Function<bool(const FS::DirectoryEntryView&)>) const override; virtual RefPtr<Inode> lookup(StringView name) override; virtual void flush_metadata() override; - virtual ssize_t write_bytes(off_t, ssize_t, const u8* buffer, FileDescription*) override; + virtual ssize_t write_bytes(off_t, ssize_t, const UserOrKernelBuffer& buffer, FileDescription*) override; virtual KResultOr<NonnullRefPtr<Inode>> create_child(const String& name, mode_t, dev_t, uid_t, gid_t) override; virtual KResult add_child(Inode&, const StringView& name, mode_t) override; virtual KResult remove_child(const StringView& name) override; diff --git a/Kernel/FileSystem/Ext2FileSystem.cpp b/Kernel/FileSystem/Ext2FileSystem.cpp index cbc9a93968..52b3037c68 100644 --- a/Kernel/FileSystem/Ext2FileSystem.cpp +++ b/Kernel/FileSystem/Ext2FileSystem.cpp @@ -88,7 +88,8 @@ bool Ext2FS::flush_super_block() { LOCKER(m_lock); ASSERT((sizeof(ext2_super_block) % logical_block_size()) == 0); - bool success = raw_write_blocks(2, (sizeof(ext2_super_block) / logical_block_size()), (const u8*)&m_super_block); + auto super_block_buffer = UserOrKernelBuffer::for_kernel_buffer((u8*)&m_super_block); + bool success = raw_write_blocks(2, (sizeof(ext2_super_block) / logical_block_size()), super_block_buffer); ASSERT(success); return true; } @@ -104,7 +105,8 @@ bool Ext2FS::initialize() { LOCKER(m_lock); ASSERT((sizeof(ext2_super_block) % logical_block_size()) == 0); - bool success = raw_read_blocks(2, (sizeof(ext2_super_block) / logical_block_size()), (u8*)&m_super_block); + auto super_block_buffer = UserOrKernelBuffer::for_kernel_buffer((u8*)&m_super_block); + bool success = raw_read_blocks(2, (sizeof(ext2_super_block) / logical_block_size()), super_block_buffer); ASSERT(success); auto& super_block = this->super_block(); @@ -139,7 +141,8 @@ bool Ext2FS::initialize() unsigned blocks_to_read = ceil_div(m_block_group_count * sizeof(ext2_group_desc), block_size()); BlockIndex first_block_of_bgdt = block_size() == 1024 ? 2 : 1; m_cached_group_descriptor_table = KBuffer::create_with_size(block_size() * blocks_to_read, Region::Access::Read | Region::Access::Write, "Ext2FS: Block group descriptors"); - read_blocks(first_block_of_bgdt, blocks_to_read, m_cached_group_descriptor_table.value().data()); + auto buffer = UserOrKernelBuffer::for_kernel_buffer(m_cached_group_descriptor_table.value().data()); + read_blocks(first_block_of_bgdt, blocks_to_read, buffer); #ifdef EXT2_DEBUG for (unsigned i = 1; i <= m_block_group_count; ++i) { @@ -291,8 +294,9 @@ bool Ext2FS::write_block_list_for_inode(InodeIndex inode_index, ext2_inode& e2in --remaining_blocks; } stream.fill_to_end(0); - bool success = write_block(e2inode.i_block[EXT2_IND_BLOCK], block_contents.data(), block_size()); - ASSERT(success); + auto buffer = UserOrKernelBuffer::for_kernel_buffer(block_contents.data()); + int err = write_block(e2inode.i_block[EXT2_IND_BLOCK], buffer, block_size()); + ASSERT(err >= 0); } if (!remaining_blocks) @@ -329,7 +333,8 @@ bool Ext2FS::write_block_list_for_inode(InodeIndex inode_index, ext2_inode& e2in memset(dind_block_contents.data(), 0, dind_block_contents.size()); dind_block_dirty = true; } else { - read_block(e2inode.i_block[EXT2_DIND_BLOCK], dind_block_contents.data(), block_size()); + auto buffer = UserOrKernelBuffer::for_kernel_buffer(dind_block_contents.data()); + read_block(e2inode.i_block[EXT2_DIND_BLOCK], &buffer, block_size()); } auto* dind_block_as_pointers = (unsigned*)dind_block_contents.data(); @@ -351,7 +356,8 @@ bool Ext2FS::write_block_list_for_inode(InodeIndex inode_index, ext2_inode& e2in memset(ind_block_contents.data(), 0, dind_block_contents.size()); ind_block_dirty = true; } else { - read_block(indirect_block_index, ind_block_contents.data(), block_size()); + auto buffer = UserOrKernelBuffer::for_kernel_buffer(ind_block_contents.data()); + read_block(indirect_block_index, &buffer, block_size()); } auto* ind_block_as_pointers = (unsigned*)ind_block_contents.data(); @@ -376,8 +382,9 @@ bool Ext2FS::write_block_list_for_inode(InodeIndex inode_index, ext2_inode& e2in } if (ind_block_dirty) { - bool success = write_block(indirect_block_index, ind_block_contents.data(), block_size()); - ASSERT(success); + auto buffer = UserOrKernelBuffer::for_kernel_buffer(ind_block_contents.data()); + int err = write_block(indirect_block_index, buffer, block_size()); + ASSERT(err >= 0); } } for (unsigned i = indirect_block_count; i < entries_per_block; ++i) { @@ -388,8 +395,9 @@ bool Ext2FS::write_block_list_for_inode(InodeIndex inode_index, ext2_inode& e2in } if (dind_block_dirty) { - bool success = write_block(e2inode.i_block[EXT2_DIND_BLOCK], dind_block_contents.data(), block_size()); - ASSERT(success); + auto buffer = UserOrKernelBuffer::for_kernel_buffer(dind_block_contents.data()); + int err = write_block(e2inode.i_block[EXT2_DIND_BLOCK], buffer, block_size()); + ASSERT(err >= 0); } } @@ -462,7 +470,8 @@ Vector<Ext2FS::BlockIndex> Ext2FS::block_list_for_inode_impl(const ext2_inode& e unsigned count = min(blocks_remaining, entries_per_block); size_t read_size = count * sizeof(__u32); auto array_block = ByteBuffer::create_uninitialized(read_size); - read_block(array_block_index, array_block.data(), read_size, 0); + auto buffer = UserOrKernelBuffer::for_kernel_buffer(array_block.data()); + read_block(array_block_index, &buffer, read_size, 0); ASSERT(array_block); auto* array = reinterpret_cast<const __u32*>(array_block.data()); for (BlockIndex i = 0; i < count; ++i) @@ -532,7 +541,8 @@ void Ext2FS::flush_block_group_descriptor_table() LOCKER(m_lock); unsigned blocks_to_write = ceil_div(m_block_group_count * sizeof(ext2_group_desc), block_size()); unsigned first_block_of_bgdt = block_size() == 1024 ? 2 : 1; - write_blocks(first_block_of_bgdt, blocks_to_write, (const u8*)block_group_descriptors()); + auto buffer = UserOrKernelBuffer::for_kernel_buffer((u8*)block_group_descriptors()); + write_blocks(first_block_of_bgdt, blocks_to_write, buffer); } void Ext2FS::flush_writes() @@ -548,7 +558,8 @@ void Ext2FS::flush_writes() } for (auto& cached_bitmap : m_cached_bitmaps) { if (cached_bitmap->dirty) { - write_block(cached_bitmap->bitmap_block_index, cached_bitmap->buffer.data(), block_size()); + auto buffer = UserOrKernelBuffer::for_kernel_buffer(cached_bitmap->buffer.data()); + write_block(cached_bitmap->bitmap_block_index, buffer, block_size()); cached_bitmap->dirty = false; #ifdef EXT2_DEBUG dbg() << "Flushed bitmap block " << cached_bitmap->bitmap_block_index; @@ -653,12 +664,13 @@ RefPtr<Inode> Ext2FS::get_inode(InodeIdentifier inode) const return {}; auto new_inode = adopt(*new Ext2FSInode(const_cast<Ext2FS&>(*this), inode.index())); - read_block(block_index, reinterpret_cast<u8*>(&new_inode->m_raw_inode), sizeof(ext2_inode), offset); + auto buffer = UserOrKernelBuffer::for_kernel_buffer(reinterpret_cast<u8*>(&new_inode->m_raw_inode)); + read_block(block_index, &buffer, sizeof(ext2_inode), offset); m_inode_cache.set(inode.index(), new_inode); return new_inode; } -ssize_t Ext2FSInode::read_bytes(off_t offset, ssize_t count, u8* buffer, FileDescription* description) const +ssize_t Ext2FSInode::read_bytes(off_t offset, ssize_t count, UserOrKernelBuffer& buffer, FileDescription* description) const { Locker inode_locker(m_lock); ASSERT(offset >= 0); @@ -670,7 +682,8 @@ ssize_t Ext2FSInode::read_bytes(off_t offset, ssize_t count, u8* buffer, FileDes if (is_symlink() && size() < max_inline_symlink_length) { ASSERT(offset == 0); ssize_t nread = min((off_t)size() - offset, static_cast<off_t>(count)); - memcpy(buffer, ((const u8*)m_raw_inode.i_block) + offset, (size_t)nread); + if (!buffer.write(((const u8*)m_raw_inode.i_block) + offset, (size_t)nread)) + return -EFAULT; return nread; } @@ -697,10 +710,9 @@ ssize_t Ext2FSInode::read_bytes(off_t offset, ssize_t count, u8* buffer, FileDes ssize_t nread = 0; size_t remaining_count = min((off_t)count, (off_t)size() - offset); - u8* out = buffer; #ifdef EXT2_DEBUG - dbg() << "Ext2FS: Reading up to " << count << " bytes " << offset << " bytes into inode " << identifier() << " to " << (const void*)buffer; + dbg() << "Ext2FS: Reading up to " << count << " bytes " << offset << " bytes into inode " << identifier() << " to " << buffer.user_or_kernel_ptr(); #endif for (size_t bi = first_block_logical_index; remaining_count && bi <= last_block_logical_index; ++bi) { @@ -708,14 +720,14 @@ ssize_t Ext2FSInode::read_bytes(off_t offset, ssize_t count, u8* buffer, FileDes ASSERT(block_index); size_t offset_into_block = (bi == first_block_logical_index) ? offset_into_first_block : 0; size_t num_bytes_to_copy = min(block_size - offset_into_block, remaining_count); - bool success = fs().read_block(block_index, out, num_bytes_to_copy, offset_into_block, allow_cache); - if (!success) { + auto buffer_offset = buffer.offset(nread); + int err = fs().read_block(block_index, &buffer_offset, num_bytes_to_copy, offset_into_block, allow_cache); + if (err < 0) { klog() << "ext2fs: read_bytes: read_block(" << block_index << ") failed (lbi: " << bi << ")"; - return -EIO; + return err; } remaining_count -= num_bytes_to_copy; nread += num_bytes_to_copy; - out += num_bytes_to_copy; } return nread; @@ -760,9 +772,9 @@ KResult Ext2FSInode::resize(u64 new_size) } } - bool success = fs().write_block_list_for_inode(index(), m_raw_inode, block_list); - if (!success) - return KResult(-EIO); + int err = fs().write_block_list_for_inode(index(), m_raw_inode, block_list); + if (err < 0) + return KResult(err); m_raw_inode.i_size = new_size; set_metadata_dirty(true); @@ -771,7 +783,7 @@ KResult Ext2FSInode::resize(u64 new_size) return KSuccess; } -ssize_t Ext2FSInode::write_bytes(off_t offset, ssize_t count, const u8* data, FileDescription* description) +ssize_t Ext2FSInode::write_bytes(off_t offset, ssize_t count, const UserOrKernelBuffer& data, FileDescription* description) { ASSERT(offset >= 0); ASSERT(count >= 0); @@ -787,9 +799,10 @@ ssize_t Ext2FSInode::write_bytes(off_t offset, ssize_t count, const u8* data, Fi ASSERT(offset == 0); if (max((size_t)(offset + count), (size_t)m_raw_inode.i_size) < max_inline_symlink_length) { #ifdef EXT2_DEBUG - dbg() << "Ext2FS: write_bytes poking into i_block array for inline symlink '" << StringView(data, count) << " ' (" << count << " bytes)"; + dbg() << "Ext2FS: write_bytes poking into i_block array for inline symlink '" << data.copy_into_string(count) << " ' (" << count << " bytes)"; #endif - memcpy(((u8*)m_raw_inode.i_block) + offset, data, (size_t)count); + if (!data.read(((u8*)m_raw_inode.i_block) + offset, (size_t)count)) + return -EFAULT; if ((size_t)(offset + count) > (size_t)m_raw_inode.i_size) m_raw_inode.i_size = offset + count; set_metadata_dirty(true); @@ -824,10 +837,9 @@ ssize_t Ext2FSInode::write_bytes(off_t offset, ssize_t count, const u8* data, Fi ssize_t nwritten = 0; size_t remaining_count = min((off_t)count, (off_t)new_size - offset); - const u8* in = data; #ifdef EXT2_DEBUG - dbg() << "Ext2FS: Writing " << count << " bytes " << offset << " bytes into inode " << identifier() << " from " << (const void*)data; + dbg() << "Ext2FS: Writing " << count << " bytes " << offset << " bytes into inode " << identifier() << " from " << data.user_or_kernel_ptr(); #endif for (size_t bi = first_block_logical_index; remaining_count && bi <= last_block_logical_index; ++bi) { @@ -836,15 +848,14 @@ ssize_t Ext2FSInode::write_bytes(off_t offset, ssize_t count, const u8* data, Fi #ifdef EXT2_DEBUG dbg() << "Ext2FS: Writing block " << m_block_list[bi] << " (offset_into_block: " << offset_into_block << ")"; #endif - bool success = fs().write_block(m_block_list[bi], in, num_bytes_to_copy, offset_into_block, allow_cache); - if (!success) { + int err = fs().write_block(m_block_list[bi], data.offset(nwritten), num_bytes_to_copy, offset_into_block, allow_cache); + if (err < 0) { dbg() << "Ext2FS: write_block(" << m_block_list[bi] << ") failed (bi: " << bi << ")"; ASSERT_NOT_REACHED(); - return -EIO; + return err; } remaining_count -= num_bytes_to_copy; nwritten += num_bytes_to_copy; - in += num_bytes_to_copy; } #ifdef EXT2_DEBUG @@ -958,7 +969,8 @@ bool Ext2FSInode::write_directory(const Vector<Ext2FSDirectoryEntry>& entries) stream.fill_to_end(0); - ssize_t nwritten = write_bytes(0, directory_data.size(), directory_data.data(), nullptr); + auto buffer = UserOrKernelBuffer::for_kernel_buffer(directory_data.data()); + ssize_t nwritten = write_bytes(0, directory_data.size(), buffer, nullptr); if (nwritten < 0) return false; set_metadata_dirty(true); @@ -1087,7 +1099,8 @@ bool Ext2FS::write_ext2_inode(unsigned inode, const ext2_inode& e2inode) unsigned offset; if (!find_block_containing_inode(inode, block_index, offset)) return false; - return write_block(block_index, reinterpret_cast<const u8*>(&e2inode), inode_size(), offset); + auto buffer = UserOrKernelBuffer::for_kernel_buffer(const_cast<u8*>((const u8*)&e2inode)); + return write_block(block_index, buffer, inode_size(), offset) >= 0; } Vector<Ext2FS::BlockIndex> Ext2FS::allocate_blocks(GroupIndex preferred_group_index, size_t count) @@ -1314,8 +1327,9 @@ Ext2FS::CachedBitmap& Ext2FS::get_bitmap_block(BlockIndex bitmap_block_index) } auto block = KBuffer::create_with_size(block_size(), Region::Access::Read | Region::Access::Write, "Ext2FS: Cached bitmap block"); - bool success = read_block(bitmap_block_index, block.data(), block_size()); - ASSERT(success); + auto buffer = UserOrKernelBuffer::for_kernel_buffer(block.data()); + int err = read_block(bitmap_block_index, &buffer, block_size()); + ASSERT(err >= 0); m_cached_bitmaps.append(make<CachedBitmap>(bitmap_block_index, move(block))); return *m_cached_bitmaps.last(); } diff --git a/Kernel/FileSystem/Ext2FileSystem.h b/Kernel/FileSystem/Ext2FileSystem.h index bdaa3255ca..7d28b84ff2 100644 --- a/Kernel/FileSystem/Ext2FileSystem.h +++ b/Kernel/FileSystem/Ext2FileSystem.h @@ -58,12 +58,12 @@ public: private: // ^Inode - virtual ssize_t read_bytes(off_t, ssize_t, u8* buffer, FileDescription*) const override; + virtual ssize_t read_bytes(off_t, ssize_t, UserOrKernelBuffer& buffer, FileDescription*) const override; virtual InodeMetadata metadata() const override; virtual KResult traverse_as_directory(Function<bool(const FS::DirectoryEntryView&)>) const override; virtual RefPtr<Inode> lookup(StringView name) override; virtual void flush_metadata() override; - virtual ssize_t write_bytes(off_t, ssize_t, const u8* data, FileDescription*) override; + virtual ssize_t write_bytes(off_t, ssize_t, const UserOrKernelBuffer& data, FileDescription*) override; virtual KResultOr<NonnullRefPtr<Inode>> create_child(const String& name, mode_t, dev_t, uid_t, gid_t) override; virtual KResult add_child(Inode& child, const StringView& name, mode_t) override; virtual KResult remove_child(const StringView& name) override; diff --git a/Kernel/FileSystem/FIFO.cpp b/Kernel/FileSystem/FIFO.cpp index 3f9c1e33a1..2aa6c55cd9 100644 --- a/Kernel/FileSystem/FIFO.cpp +++ b/Kernel/FileSystem/FIFO.cpp @@ -145,14 +145,14 @@ bool FIFO::can_write(const FileDescription&, size_t) const return m_buffer.space_for_writing() || !m_readers; } -KResultOr<size_t> FIFO::read(FileDescription&, size_t, u8* buffer, size_t size) +KResultOr<size_t> FIFO::read(FileDescription&, size_t, UserOrKernelBuffer& buffer, size_t size) { if (!m_writers && m_buffer.is_empty()) return 0; return m_buffer.read(buffer, size); } -KResultOr<size_t> FIFO::write(FileDescription&, size_t, const u8* buffer, size_t size) +KResultOr<size_t> FIFO::write(FileDescription&, size_t, const UserOrKernelBuffer& buffer, size_t size) { if (!m_readers) { Thread::current()->send_signal(SIGPIPE, Process::current()); diff --git a/Kernel/FileSystem/FIFO.h b/Kernel/FileSystem/FIFO.h index 81b04597f2..8e3a146012 100644 --- a/Kernel/FileSystem/FIFO.h +++ b/Kernel/FileSystem/FIFO.h @@ -57,8 +57,8 @@ public: private: // ^File - virtual KResultOr<size_t> write(FileDescription&, size_t, const u8*, size_t) override; - virtual KResultOr<size_t> read(FileDescription&, size_t, u8*, size_t) override; + virtual KResultOr<size_t> write(FileDescription&, size_t, const UserOrKernelBuffer&, size_t) override; + virtual KResultOr<size_t> read(FileDescription&, size_t, UserOrKernelBuffer&, size_t) override; virtual KResult stat(::stat&) const override; virtual bool can_read(const FileDescription&, size_t) const override; virtual bool can_write(const FileDescription&, size_t) const override; diff --git a/Kernel/FileSystem/File.h b/Kernel/FileSystem/File.h index 150f04f518..b2400b803b 100644 --- a/Kernel/FileSystem/File.h +++ b/Kernel/FileSystem/File.h @@ -34,6 +34,7 @@ #include <Kernel/Forward.h> #include <Kernel/KResult.h> #include <Kernel/UnixTypes.h> +#include <Kernel/UserOrKernelBuffer.h> #include <Kernel/VirtualAddress.h> namespace Kernel { @@ -77,8 +78,8 @@ public: virtual bool can_read(const FileDescription&, size_t) const = 0; virtual bool can_write(const FileDescription&, size_t) const = 0; - virtual KResultOr<size_t> read(FileDescription&, size_t, u8*, size_t) = 0; - virtual KResultOr<size_t> write(FileDescription&, size_t, const u8*, size_t) = 0; + virtual KResultOr<size_t> read(FileDescription&, size_t, UserOrKernelBuffer&, size_t) = 0; + virtual KResultOr<size_t> write(FileDescription&, size_t, const UserOrKernelBuffer&, size_t) = 0; virtual int ioctl(FileDescription&, unsigned request, FlatPtr arg); virtual KResultOr<Region*> mmap(Process&, FileDescription&, VirtualAddress preferred_vaddr, size_t offset, size_t size, int prot, bool shared); virtual KResult stat(::stat&) const { return KResult(-EBADF); } diff --git a/Kernel/FileSystem/FileDescription.cpp b/Kernel/FileSystem/FileDescription.cpp index 80153e6225..8c88dfc816 100644 --- a/Kernel/FileSystem/FileDescription.cpp +++ b/Kernel/FileSystem/FileDescription.cpp @@ -116,7 +116,7 @@ off_t FileDescription::seek(off_t offset, int whence) return m_current_offset; } -KResultOr<size_t> FileDescription::read(u8* buffer, size_t count) +KResultOr<size_t> FileDescription::read(UserOrKernelBuffer& buffer, size_t count) { LOCKER(m_lock); Checked<size_t> new_offset = m_current_offset; @@ -130,7 +130,7 @@ KResultOr<size_t> FileDescription::read(u8* buffer, size_t count) return nread_or_error; } -KResultOr<size_t> FileDescription::write(const u8* data, size_t size) +KResultOr<size_t> FileDescription::write(const UserOrKernelBuffer& data, size_t size) { LOCKER(m_lock); Checked<size_t> new_offset = m_current_offset; @@ -162,7 +162,7 @@ KResultOr<KBuffer> FileDescription::read_entire_file() return m_inode->read_entire(this); } -ssize_t FileDescription::get_dir_entries(u8* buffer, ssize_t size) +ssize_t FileDescription::get_dir_entries(UserOrKernelBuffer& buffer, ssize_t size) { LOCKER(m_lock, Lock::Mode::Shared); if (!is_directory()) @@ -195,7 +195,8 @@ ssize_t FileDescription::get_dir_entries(u8* buffer, ssize_t size) if (static_cast<size_t>(size) < temp_buffer.size()) return -EINVAL; - copy_to_user(buffer, temp_buffer.data(), temp_buffer.size()); + if (!buffer.write(temp_buffer.data(), temp_buffer.size())) + return -EFAULT; return stream.offset(); } diff --git a/Kernel/FileSystem/FileDescription.h b/Kernel/FileSystem/FileDescription.h index 3427ad1e18..60d85db945 100644 --- a/Kernel/FileSystem/FileDescription.h +++ b/Kernel/FileSystem/FileDescription.h @@ -60,8 +60,8 @@ public: KResult close(); off_t seek(off_t, int whence); - KResultOr<size_t> read(u8*, size_t); - KResultOr<size_t> write(const u8* data, size_t); + KResultOr<size_t> read(UserOrKernelBuffer&, size_t); + KResultOr<size_t> write(const UserOrKernelBuffer& data, size_t); KResult stat(::stat&); KResult chmod(mode_t); @@ -69,7 +69,7 @@ public: bool can_read() const; bool can_write() const; - ssize_t get_dir_entries(u8* buffer, ssize_t); + ssize_t get_dir_entries(UserOrKernelBuffer& buffer, ssize_t); KResultOr<KBuffer> read_entire_file(); diff --git a/Kernel/FileSystem/FileSystem.h b/Kernel/FileSystem/FileSystem.h index 19fea4bafd..99a8131ca4 100644 --- a/Kernel/FileSystem/FileSystem.h +++ b/Kernel/FileSystem/FileSystem.h @@ -34,6 +34,7 @@ #include <Kernel/KResult.h> #include <Kernel/Lock.h> #include <Kernel/UnixTypes.h> +#include <Kernel/UserOrKernelBuffer.h> namespace Kernel { diff --git a/Kernel/FileSystem/Inode.cpp b/Kernel/FileSystem/Inode.cpp index e78f87bf59..b0e91bafc5 100644 --- a/Kernel/FileSystem/Inode.cpp +++ b/Kernel/FileSystem/Inode.cpp @@ -73,7 +73,10 @@ KResultOr<KBuffer> Inode::read_entire(FileDescription* descriptor) const u8 buffer[4096]; off_t offset = 0; for (;;) { - nread = read_bytes(offset, sizeof(buffer), buffer, descriptor); + auto buf = UserOrKernelBuffer::for_kernel_buffer(buffer); + nread = read_bytes(offset, sizeof(buffer), buf, descriptor); + if (nread < 0) + return KResult(nread); ASSERT(nread <= (ssize_t)sizeof(buffer)); if (nread <= 0) break; @@ -124,7 +127,7 @@ void Inode::will_be_destroyed() flush_metadata(); } -void Inode::inode_contents_changed(off_t offset, ssize_t size, const u8* data) +void Inode::inode_contents_changed(off_t offset, ssize_t size, const UserOrKernelBuffer& data) { if (m_shared_vmobject) m_shared_vmobject->inode_contents_changed({}, offset, size, data); diff --git a/Kernel/FileSystem/Inode.h b/Kernel/FileSystem/Inode.h index f9ed0db158..d506ab0d18 100644 --- a/Kernel/FileSystem/Inode.h +++ b/Kernel/FileSystem/Inode.h @@ -69,10 +69,10 @@ public: KResultOr<KBuffer> read_entire(FileDescription* = nullptr) const; - virtual ssize_t read_bytes(off_t, ssize_t, u8* buffer, FileDescription*) const = 0; + virtual ssize_t read_bytes(off_t, ssize_t, UserOrKernelBuffer& buffer, FileDescription*) const = 0; virtual KResult traverse_as_directory(Function<bool(const FS::DirectoryEntryView&)>) const = 0; virtual RefPtr<Inode> lookup(StringView name) = 0; - virtual ssize_t write_bytes(off_t, ssize_t, const u8* data, FileDescription*) = 0; + virtual ssize_t write_bytes(off_t, ssize_t, const UserOrKernelBuffer& data, FileDescription*) = 0; virtual KResultOr<NonnullRefPtr<Inode>> create_child(const String& name, mode_t, dev_t, uid_t, gid_t) = 0; virtual KResult add_child(Inode&, const StringView& name, mode_t) = 0; virtual KResult remove_child(const StringView& name) = 0; @@ -122,7 +122,7 @@ public: protected: Inode(FS& fs, unsigned index); void set_metadata_dirty(bool); - void inode_contents_changed(off_t, ssize_t, const u8*); + void inode_contents_changed(off_t, ssize_t, const UserOrKernelBuffer&); void inode_size_changed(size_t old_size, size_t new_size); KResult prepare_to_write_data(); diff --git a/Kernel/FileSystem/InodeFile.cpp b/Kernel/FileSystem/InodeFile.cpp index c2657fe969..bc4d243957 100644 --- a/Kernel/FileSystem/InodeFile.cpp +++ b/Kernel/FileSystem/InodeFile.cpp @@ -44,7 +44,7 @@ InodeFile::~InodeFile() { } -KResultOr<size_t> InodeFile::read(FileDescription& description, size_t offset, u8* buffer, size_t count) +KResultOr<size_t> InodeFile::read(FileDescription& description, size_t offset, UserOrKernelBuffer& buffer, size_t count) { ssize_t nread = m_inode->read_bytes(offset, count, buffer, &description); if (nread > 0) @@ -54,7 +54,7 @@ KResultOr<size_t> InodeFile::read(FileDescription& description, size_t offset, u return nread; } -KResultOr<size_t> InodeFile::write(FileDescription& description, size_t offset, const u8* data, size_t count) +KResultOr<size_t> InodeFile::write(FileDescription& description, size_t offset, const UserOrKernelBuffer& data, size_t count) { ssize_t nwritten = m_inode->write_bytes(offset, count, data, &description); if (nwritten > 0) { diff --git a/Kernel/FileSystem/InodeFile.h b/Kernel/FileSystem/InodeFile.h index ab64201b3b..e051476b2b 100644 --- a/Kernel/FileSystem/InodeFile.h +++ b/Kernel/FileSystem/InodeFile.h @@ -47,8 +47,8 @@ public: virtual bool can_read(const FileDescription&, size_t) const override { return true; } virtual bool can_write(const FileDescription&, size_t) const override { return true; } - virtual KResultOr<size_t> read(FileDescription&, size_t, u8*, size_t) override; - virtual KResultOr<size_t> write(FileDescription&, size_t, const u8*, size_t) override; + virtual KResultOr<size_t> read(FileDescription&, size_t, UserOrKernelBuffer&, size_t) override; + virtual KResultOr<size_t> write(FileDescription&, size_t, const UserOrKernelBuffer&, size_t) override; virtual KResultOr<Region*> mmap(Process&, FileDescription&, VirtualAddress preferred_vaddr, size_t offset, size_t size, int prot, bool shared) override; virtual String absolute_path(const FileDescription&) const override; diff --git a/Kernel/FileSystem/InodeWatcher.cpp b/Kernel/FileSystem/InodeWatcher.cpp index a4612a588d..6e76cc69b6 100644 --- a/Kernel/FileSystem/InodeWatcher.cpp +++ b/Kernel/FileSystem/InodeWatcher.cpp @@ -57,7 +57,7 @@ bool InodeWatcher::can_write(const FileDescription&, size_t) const return true; } -KResultOr<size_t> InodeWatcher::read(FileDescription&, size_t, u8* buffer, size_t buffer_size) +KResultOr<size_t> InodeWatcher::read(FileDescription&, size_t, UserOrKernelBuffer& buffer, size_t buffer_size) { LOCKER(m_lock); ASSERT(!m_queue.is_empty() || !m_inode); @@ -68,11 +68,17 @@ KResultOr<size_t> InodeWatcher::read(FileDescription&, size_t, u8* buffer, size_ // FIXME: What should we do if the output buffer is too small? ASSERT(buffer_size >= (int)sizeof(Event)); auto event = m_queue.dequeue(); - memcpy(buffer, &event, sizeof(event)); + ssize_t nwritten = buffer.write_buffered<sizeof(event)>(sizeof(event), [&](u8* data, size_t data_bytes) { + memcpy(data, &event, sizeof(event)); + return (ssize_t)data_bytes; + }); + if (nwritten < 0) + return KResult(nwritten); + ASSERT((size_t)nwritten == sizeof(event)); return sizeof(event); } -KResultOr<size_t> InodeWatcher::write(FileDescription&, size_t, const u8*, size_t) +KResultOr<size_t> InodeWatcher::write(FileDescription&, size_t, const UserOrKernelBuffer&, size_t) { return KResult(-EIO); } diff --git a/Kernel/FileSystem/InodeWatcher.h b/Kernel/FileSystem/InodeWatcher.h index 31a094b88f..cd371e2f1a 100644 --- a/Kernel/FileSystem/InodeWatcher.h +++ b/Kernel/FileSystem/InodeWatcher.h @@ -55,8 +55,8 @@ public: virtual bool can_read(const FileDescription&, size_t) const override; virtual bool can_write(const FileDescription&, size_t) const override; - virtual KResultOr<size_t> read(FileDescription&, size_t, u8*, size_t) override; - virtual KResultOr<size_t> write(FileDescription&, size_t, const u8*, size_t) override; + virtual KResultOr<size_t> read(FileDescription&, size_t, UserOrKernelBuffer&, size_t) override; + virtual KResultOr<size_t> write(FileDescription&, size_t, const UserOrKernelBuffer&, size_t) override; virtual String absolute_path(const FileDescription&) const override; virtual const char* class_name() const override { return "InodeWatcher"; }; diff --git a/Kernel/FileSystem/Plan9FileSystem.cpp b/Kernel/FileSystem/Plan9FileSystem.cpp index 952a176066..975883df67 100644 --- a/Kernel/FileSystem/Plan9FileSystem.cpp +++ b/Kernel/FileSystem/Plan9FileSystem.cpp @@ -426,7 +426,8 @@ KResult Plan9FS::post_message(Message& message) if (Thread::current()->block<Thread::WriteBlocker>(nullptr, description).was_interrupted()) return KResult(-EINTR); } - auto nwritten_or_error = description.write(data, size); + auto data_buffer = UserOrKernelBuffer::for_kernel_buffer(const_cast<u8*>(data)); + auto nwritten_or_error = description.write(data_buffer, size); if (nwritten_or_error.is_error()) return nwritten_or_error.error(); auto nwritten = nwritten_or_error.value(); @@ -445,7 +446,8 @@ KResult Plan9FS::do_read(u8* data, size_t size) if (Thread::current()->block<Thread::ReadBlocker>(nullptr, description).was_interrupted()) return KResult(-EINTR); } - auto nread_or_error = description.read(data, size); + auto data_buffer = UserOrKernelBuffer::for_kernel_buffer(data); + auto nread_or_error = description.read(data_buffer, size); if (nread_or_error.is_error()) return nread_or_error.error(); auto nread = nread_or_error.value(); @@ -677,7 +679,7 @@ KResult Plan9FSInode::ensure_open_for_mode(int mode) } } -ssize_t Plan9FSInode::read_bytes(off_t offset, ssize_t size, u8* buffer, FileDescription*) const +ssize_t Plan9FSInode::read_bytes(off_t offset, ssize_t size, UserOrKernelBuffer& buffer, FileDescription*) const { auto result = const_cast<Plan9FSInode&>(*this).ensure_open_for_mode(O_RDONLY); if (result.is_error()) @@ -710,12 +712,13 @@ ssize_t Plan9FSInode::read_bytes(off_t offset, ssize_t size, u8* buffer, FileDes // Guard against the server returning more data than requested. size_t nread = min(data.length(), (size_t)size); - memcpy(buffer, data.characters_without_null_termination(), nread); + if (!buffer.write(data.characters_without_null_termination(), nread)) + return -EFAULT; return nread; } -ssize_t Plan9FSInode::write_bytes(off_t offset, ssize_t size, const u8* data, FileDescription*) +ssize_t Plan9FSInode::write_bytes(off_t offset, ssize_t size, const UserOrKernelBuffer& data, FileDescription*) { auto result = ensure_open_for_mode(O_WRONLY); if (result.is_error()) @@ -723,9 +726,13 @@ ssize_t Plan9FSInode::write_bytes(off_t offset, ssize_t size, const u8* data, Fi size = fs().adjust_buffer_size(size); + auto data_copy = data.copy_into_string(size); // FIXME: this seems ugly + if (data_copy.is_null()) + return -EFAULT; + Plan9FS::Message message { fs(), Plan9FS::Message::Type::Twrite }; message << fid() << (u64)offset; - message.append_data({ data, (size_t)size }); + message.append_data(data_copy); result = fs().post_message_and_wait_for_a_reply(message); if (result.is_error()) return result.error(); diff --git a/Kernel/FileSystem/Plan9FileSystem.h b/Kernel/FileSystem/Plan9FileSystem.h index 77af39e47a..5851cbe8dd 100644 --- a/Kernel/FileSystem/Plan9FileSystem.h +++ b/Kernel/FileSystem/Plan9FileSystem.h @@ -124,8 +124,8 @@ public: // ^Inode virtual InodeMetadata metadata() const override; virtual void flush_metadata() override; - virtual ssize_t read_bytes(off_t, ssize_t, u8* buffer, FileDescription*) const override; - virtual ssize_t write_bytes(off_t, ssize_t, const u8* data, FileDescription*) override; + virtual ssize_t read_bytes(off_t, ssize_t, UserOrKernelBuffer& buffer, FileDescription*) const override; + virtual ssize_t write_bytes(off_t, ssize_t, const UserOrKernelBuffer& data, FileDescription*) override; virtual KResult traverse_as_directory(Function<bool(const FS::DirectoryEntryView&)>) const override; virtual RefPtr<Inode> lookup(StringView name) override; virtual KResultOr<NonnullRefPtr<Inode>> create_child(const String& name, mode_t, dev_t, uid_t, gid_t) override; diff --git a/Kernel/FileSystem/ProcFS.cpp b/Kernel/FileSystem/ProcFS.cpp index 0fe482cf36..eef030b29f 100644 --- a/Kernel/FileSystem/ProcFS.cpp +++ b/Kernel/FileSystem/ProcFS.cpp @@ -976,21 +976,33 @@ static ByteBuffer read_sys_bool(InodeIdentifier inode_id) return buffer; } -static ssize_t write_sys_bool(InodeIdentifier inode_id, const ByteBuffer& data) +static ssize_t write_sys_bool(InodeIdentifier inode_id, const UserOrKernelBuffer& buffer, size_t size) { auto& variable = SysVariable::for_inode(inode_id); ASSERT(variable.type == SysVariable::Type::Boolean); - if (data.is_empty() || !(data[0] == '0' || data[0] == '1')) - return data.size(); + char value = 0; + bool did_read = false; + ssize_t nread = buffer.read_buffered<1>(1, [&](const u8* data, size_t) { + if (did_read) + return 0; + value = (char)data[0]; + did_read = true; + return 1; + }); + if (nread < 0) + return nread; + ASSERT(nread == 0 || (nread == 1 && did_read)); + if (nread == 0 || !(value == '0' || value == '1')) + return (ssize_t)size; auto* lockable_bool = reinterpret_cast<Lockable<bool>*>(variable.address); { LOCKER(lockable_bool->lock()); - lockable_bool->resource() = data[0] == '1'; + lockable_bool->resource() = value == '1'; } variable.notify(); - return data.size(); + return (ssize_t)size; } static ByteBuffer read_sys_string(InodeIdentifier inode_id) @@ -1003,18 +1015,22 @@ static ByteBuffer read_sys_string(InodeIdentifier inode_id) return lockable_string->resource().to_byte_buffer(); } -static ssize_t write_sys_string(InodeIdentifier inode_id, const ByteBuffer& data) +static ssize_t write_sys_string(InodeIdentifier inode_id, const UserOrKernelBuffer& buffer, size_t size) { auto& variable = SysVariable::for_inode(inode_id); ASSERT(variable.type == SysVariable::Type::String); + auto string_copy = buffer.copy_into_string(size); + if (string_copy.is_null()) + return -EFAULT; + { auto* lockable_string = reinterpret_cast<Lockable<String>*>(variable.address); LOCKER(lockable_string->lock()); - lockable_string->resource() = String((const char*)data.data(), data.size()); + lockable_string->resource() = move(string_copy); } variable.notify(); - return data.size(); + return (ssize_t)size; } void ProcFS::add_sys_bool(String&& name, Lockable<bool>& var, Function<void()>&& notify_callback) @@ -1180,13 +1196,13 @@ InodeMetadata ProcFSInode::metadata() const return metadata; } -ssize_t ProcFSInode::read_bytes(off_t offset, ssize_t count, u8* buffer, FileDescription* description) const +ssize_t ProcFSInode::read_bytes(off_t offset, ssize_t count, UserOrKernelBuffer& buffer, FileDescription* description) const { #ifdef PROCFS_DEBUG dbg() << "ProcFS: read_bytes " << index(); #endif ASSERT(offset >= 0); - ASSERT(buffer); + ASSERT(buffer.user_or_kernel_ptr()); auto* directory_entry = fs().get_directory_entry(identifier()); @@ -1240,7 +1256,8 @@ ssize_t ProcFSInode::read_bytes(off_t offset, ssize_t count, u8* buffer, FileDes return 0; ssize_t nread = min(static_cast<off_t>(data.value().size() - offset), static_cast<off_t>(count)); - memcpy(buffer, data.value().data() + offset, nread); + if (!buffer.write(data.value().data() + offset, nread)) + return -EFAULT; if (nread == 0 && description && description->generator_cache().has_value()) description->generator_cache().clear(); @@ -1461,7 +1478,7 @@ void ProcFSInode::flush_metadata() { } -ssize_t ProcFSInode::write_bytes(off_t offset, ssize_t size, const u8* buffer, FileDescription*) +ssize_t ProcFSInode::write_bytes(off_t offset, ssize_t size, const UserOrKernelBuffer& buffer, FileDescription*) { auto result = prepare_to_write_data(); if (result.is_error()) @@ -1469,8 +1486,8 @@ ssize_t ProcFSInode::write_bytes(off_t offset, ssize_t size, const u8* buffer, F auto* directory_entry = fs().get_directory_entry(identifier()); - Function<ssize_t(InodeIdentifier, const ByteBuffer&)> callback_tmp; - Function<ssize_t(InodeIdentifier, const ByteBuffer&)>* write_callback { nullptr }; + Function<ssize_t(InodeIdentifier, const UserOrKernelBuffer&, size_t)> callback_tmp; + Function<ssize_t(InodeIdentifier, const UserOrKernelBuffer&, size_t)>* write_callback { nullptr }; if (directory_entry == nullptr) { if (to_proc_parent_directory(identifier()) == PDI_Root_sys) { @@ -1496,9 +1513,10 @@ ssize_t ProcFSInode::write_bytes(off_t offset, ssize_t size, const u8* buffer, F ASSERT(is_persistent_inode(identifier())); // FIXME: Being able to write into ProcFS at a non-zero offset seems like something we should maybe support.. ASSERT(offset == 0); - bool success = (*write_callback)(identifier(), ByteBuffer::wrap(const_cast<u8*>(buffer), size)); - ASSERT(success); - return 0; + ssize_t nwritten = (*write_callback)(identifier(), buffer, (size_t)size); + if (nwritten < 0) + klog() << "ProcFS: Writing " << size << " bytes failed: " << nwritten; + return nwritten; } KResultOr<NonnullRefPtr<Custody>> ProcFSInode::resolve_as_link(Custody& base, RefPtr<Custody>* out_parent, int options, int symlink_recursion_level) const diff --git a/Kernel/FileSystem/ProcFS.h b/Kernel/FileSystem/ProcFS.h index a68df543f0..5d2d3fb124 100644 --- a/Kernel/FileSystem/ProcFS.h +++ b/Kernel/FileSystem/ProcFS.h @@ -59,7 +59,7 @@ private: struct ProcFSDirectoryEntry { ProcFSDirectoryEntry() { } - ProcFSDirectoryEntry(const char* a_name, unsigned a_proc_file_type, bool a_supervisor_only, Function<Optional<KBuffer>(InodeIdentifier)>&& a_read_callback = nullptr, Function<ssize_t(InodeIdentifier, const ByteBuffer&)>&& a_write_callback = nullptr, RefPtr<ProcFSInode>&& a_inode = nullptr) + ProcFSDirectoryEntry(const char* a_name, unsigned a_proc_file_type, bool a_supervisor_only, Function<Optional<KBuffer>(InodeIdentifier)>&& a_read_callback = nullptr, Function<ssize_t(InodeIdentifier, const UserOrKernelBuffer&, size_t)>&& a_write_callback = nullptr, RefPtr<ProcFSInode>&& a_inode = nullptr) : name(a_name) , proc_file_type(a_proc_file_type) , supervisor_only(a_supervisor_only) @@ -73,7 +73,7 @@ private: unsigned proc_file_type { 0 }; bool supervisor_only { false }; Function<Optional<KBuffer>(InodeIdentifier)> read_callback; - Function<ssize_t(InodeIdentifier, const ByteBuffer&)> write_callback; + Function<ssize_t(InodeIdentifier, const UserOrKernelBuffer&, size_t)> write_callback; RefPtr<ProcFSInode> inode; InodeIdentifier identifier(unsigned fsid) const; }; @@ -96,12 +96,12 @@ public: private: // ^Inode - virtual ssize_t read_bytes(off_t, ssize_t, u8* buffer, FileDescription*) const override; + virtual ssize_t read_bytes(off_t, ssize_t, UserOrKernelBuffer& buffer, FileDescription*) const override; virtual InodeMetadata metadata() const override; virtual KResult traverse_as_directory(Function<bool(const FS::DirectoryEntryView&)>) const override; virtual RefPtr<Inode> lookup(StringView name) override; virtual void flush_metadata() override; - virtual ssize_t write_bytes(off_t, ssize_t, const u8* buffer, FileDescription*) override; + virtual ssize_t write_bytes(off_t, ssize_t, const UserOrKernelBuffer& buffer, FileDescription*) override; virtual KResultOr<NonnullRefPtr<Inode>> create_child(const String& name, mode_t, dev_t, uid_t, gid_t) override; virtual KResult add_child(Inode&, const StringView& name, mode_t) override; virtual KResult remove_child(const StringView& name) override; @@ -123,12 +123,12 @@ public: private: // ^Inode - virtual ssize_t read_bytes(off_t, ssize_t, u8*, FileDescription*) const override { ASSERT_NOT_REACHED(); } + virtual ssize_t read_bytes(off_t, ssize_t, UserOrKernelBuffer&, FileDescription*) const override { ASSERT_NOT_REACHED(); } virtual InodeMetadata metadata() const override; virtual KResult traverse_as_directory(Function<bool(const FS::DirectoryEntryView&)>) const override { ASSERT_NOT_REACHED(); } virtual RefPtr<Inode> lookup(StringView name) override; virtual void flush_metadata() override {}; - virtual ssize_t write_bytes(off_t, ssize_t, const u8*, FileDescription*) override { ASSERT_NOT_REACHED(); } + virtual ssize_t write_bytes(off_t, ssize_t, const UserOrKernelBuffer&, FileDescription*) override { ASSERT_NOT_REACHED(); } virtual KResultOr<NonnullRefPtr<Inode>> create_child(const String& name, mode_t, dev_t, uid_t, gid_t) override; virtual KResult add_child(Inode&, const StringView& name, mode_t) override; virtual KResult remove_child(const StringView& name) override; diff --git a/Kernel/FileSystem/TmpFS.cpp b/Kernel/FileSystem/TmpFS.cpp index 04ac98d33d..31222d6e87 100644 --- a/Kernel/FileSystem/TmpFS.cpp +++ b/Kernel/FileSystem/TmpFS.cpp @@ -141,7 +141,7 @@ KResult TmpFSInode::traverse_as_directory(Function<bool(const FS::DirectoryEntry return KSuccess; } -ssize_t TmpFSInode::read_bytes(off_t offset, ssize_t size, u8* buffer, FileDescription*) const +ssize_t TmpFSInode::read_bytes(off_t offset, ssize_t size, UserOrKernelBuffer& buffer, FileDescription*) const { LOCKER(m_lock, Lock::Mode::Shared); ASSERT(!is_directory()); @@ -157,11 +157,12 @@ ssize_t TmpFSInode::read_bytes(off_t offset, ssize_t size, u8* buffer, FileDescr if (static_cast<off_t>(size) > m_metadata.size - offset) size = m_metadata.size - offset; - memcpy(buffer, m_content.value().data() + offset, size); + if (!buffer.write(m_content.value().data() + offset, size)) + return -EFAULT; return size; } -ssize_t TmpFSInode::write_bytes(off_t offset, ssize_t size, const u8* buffer, FileDescription*) +ssize_t TmpFSInode::write_bytes(off_t offset, ssize_t size, const UserOrKernelBuffer& buffer, FileDescription*) { LOCKER(m_lock); ASSERT(!is_directory()); @@ -199,7 +200,8 @@ ssize_t TmpFSInode::write_bytes(off_t offset, ssize_t size, const u8* buffer, Fi inode_size_changed(old_size, new_size); } - memcpy(m_content.value().data() + offset, buffer, size); + if (!buffer.read(m_content.value().data() + offset, size)) // TODO: partial reads? + return -EFAULT; inode_contents_changed(offset, size, buffer); return size; @@ -343,8 +345,10 @@ KResult TmpFSInode::truncate(u64 size) if (old_size != (size_t)size) { inode_size_changed(old_size, size); - if (m_content.has_value()) - inode_contents_changed(0, size, m_content.value().data()); + if (m_content.has_value()) { + auto buffer = UserOrKernelBuffer::for_kernel_buffer(m_content.value().data()); + inode_contents_changed(0, size, buffer); + } } return KSuccess; diff --git a/Kernel/FileSystem/TmpFS.h b/Kernel/FileSystem/TmpFS.h index bb77e6b946..02eed3f17f 100644 --- a/Kernel/FileSystem/TmpFS.h +++ b/Kernel/FileSystem/TmpFS.h @@ -74,12 +74,12 @@ public: const TmpFS& fs() const { return static_cast<const TmpFS&>(Inode::fs()); } // ^Inode - virtual ssize_t read_bytes(off_t, ssize_t, u8* buffer, FileDescription*) const override; + virtual ssize_t read_bytes(off_t, ssize_t, UserOrKernelBuffer& buffer, FileDescription*) const override; virtual InodeMetadata metadata() const override; virtual KResult traverse_as_directory(Function<bool(const FS::DirectoryEntryView&)>) const override; virtual RefPtr<Inode> lookup(StringView name) override; virtual void flush_metadata() override; - virtual ssize_t write_bytes(off_t, ssize_t, const u8* buffer, FileDescription*) override; + virtual ssize_t write_bytes(off_t, ssize_t, const UserOrKernelBuffer& buffer, FileDescription*) override; virtual KResultOr<NonnullRefPtr<Inode>> create_child(const String& name, mode_t, dev_t, uid_t, gid_t) override; virtual KResult add_child(Inode&, const StringView& name, mode_t) override; virtual KResult remove_child(const StringView& name) override; diff --git a/Kernel/FileSystem/VirtualFileSystem.cpp b/Kernel/FileSystem/VirtualFileSystem.cpp index ea06d462c3..c0c93dfecb 100644 --- a/Kernel/FileSystem/VirtualFileSystem.cpp +++ b/Kernel/FileSystem/VirtualFileSystem.cpp @@ -707,7 +707,8 @@ KResult VFS::symlink(StringView target, StringView linkpath, Custody& base) if (inode_or_error.is_error()) return inode_or_error.error(); auto& inode = inode_or_error.value(); - ssize_t nwritten = inode->write_bytes(0, target.length(), (const u8*)target.characters_without_null_termination(), nullptr); + auto target_buffer = UserOrKernelBuffer::for_kernel_buffer(const_cast<u8*>((const u8*)target.characters_without_null_termination())); + ssize_t nwritten = inode->write_bytes(0, target.length(), target_buffer, nullptr); if (nwritten < 0) return KResult(nwritten); return KSuccess; |