1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 18:28:12 +00:00

Kernel: Make copy_to/from_user safe and remove unnecessary checks

Since the CPU already does almost all necessary validation steps
for us, we don't really need to attempt to do this. Doing it
ourselves doesn't really work very reliably, because we'd have to
account for other processors modifying virtual memory, and we'd
have to account for e.g. pages not being able to be allocated
due to insufficient resources.

So change the copy_to/from_user (and associated helper functions)
to use the new safe_memcpy, which will return whether it succeeded
or not. The only manual validation step needed (which the CPU
can't perform for us) is making sure the pointers provided by user
mode aren't pointing to kernel mappings.

To make it easier to read/write from/to either kernel or user mode
data add the UserOrKernelBuffer helper class, which will internally
either use copy_from/to_user or directly memcpy, or pass the data
through directly using a temporary buffer on the stack.

Last but not least we need to keep syscall params trivial as we
need to copy them from/to user mode using copy_from/to_user.
This commit is contained in:
Tom 2020-09-11 21:11:07 -06:00 committed by Andreas Kling
parent 7d1b8417bd
commit c8d9f1b9c9
149 changed files with 1585 additions and 1244 deletions

View file

@ -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;
});

View file

@ -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 };

View file

@ -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();
}

View file

@ -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;

View file

@ -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();
}

View file

@ -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;

View file

@ -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());

View file

@ -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;

View file

@ -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); }

View file

@ -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();
}

View file

@ -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();

View file

@ -34,6 +34,7 @@
#include <Kernel/KResult.h>
#include <Kernel/Lock.h>
#include <Kernel/UnixTypes.h>
#include <Kernel/UserOrKernelBuffer.h>
namespace Kernel {

View file

@ -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);

View file

@ -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();

View file

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

View file

@ -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;

View file

@ -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);
}

View file

@ -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"; };

View file

@ -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();

View file

@ -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;

View file

@ -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

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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;