Serenity Operating System
1/*
2 * Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 */
6
7#include <Kernel/FileSystem/Inode.h>
8#include <Kernel/Locking/Spinlock.h>
9#include <Kernel/Memory/SharedInodeVMObject.h>
10
11namespace Kernel::Memory {
12
13ErrorOr<NonnullLockRefPtr<SharedInodeVMObject>> SharedInodeVMObject::try_create_with_inode(Inode& inode)
14{
15 if (inode.size() == 0)
16 return EINVAL;
17 return try_create_with_inode_and_range(inode, 0, inode.size());
18}
19
20ErrorOr<NonnullLockRefPtr<SharedInodeVMObject>> SharedInodeVMObject::try_create_with_inode_and_range(Inode& inode, u64 offset, size_t range_size)
21{
22 // Note: To ensure further allocation of a Region with this VMObject will not complain
23 // on "smaller" VMObject than the requested Region, we simply take the max size between both values.
24 auto size = max(inode.size(), (offset + range_size));
25 VERIFY(size > 0);
26 if (auto shared_vmobject = inode.shared_vmobject())
27 return shared_vmobject.release_nonnull();
28 auto new_physical_pages = TRY(VMObject::try_create_physical_pages(size));
29 auto dirty_pages = TRY(Bitmap::create(new_physical_pages.size(), false));
30 auto vmobject = TRY(adopt_nonnull_lock_ref_or_enomem(new (nothrow) SharedInodeVMObject(inode, move(new_physical_pages), move(dirty_pages))));
31 TRY(vmobject->inode().set_shared_vmobject(*vmobject));
32 return vmobject;
33}
34
35ErrorOr<NonnullLockRefPtr<VMObject>> SharedInodeVMObject::try_clone()
36{
37 auto new_physical_pages = TRY(this->try_clone_physical_pages());
38 auto dirty_pages = TRY(Bitmap::create(new_physical_pages.size(), false));
39 return adopt_nonnull_lock_ref_or_enomem<VMObject>(new (nothrow) SharedInodeVMObject(*this, move(new_physical_pages), move(dirty_pages)));
40}
41
42SharedInodeVMObject::SharedInodeVMObject(Inode& inode, FixedArray<RefPtr<PhysicalPage>>&& new_physical_pages, Bitmap dirty_pages)
43 : InodeVMObject(inode, move(new_physical_pages), move(dirty_pages))
44{
45}
46
47SharedInodeVMObject::SharedInodeVMObject(SharedInodeVMObject const& other, FixedArray<RefPtr<PhysicalPage>>&& new_physical_pages, Bitmap dirty_pages)
48 : InodeVMObject(other, move(new_physical_pages), move(dirty_pages))
49{
50}
51
52ErrorOr<void> SharedInodeVMObject::sync(off_t offset_in_pages, size_t pages)
53{
54 SpinlockLocker locker(m_lock);
55
56 size_t highest_page_to_flush = min(page_count(), offset_in_pages + pages);
57
58 for (size_t page_index = offset_in_pages; page_index < highest_page_to_flush; ++page_index) {
59 auto& physical_page = m_physical_pages[page_index];
60 if (!physical_page)
61 continue;
62
63 u8 page_buffer[PAGE_SIZE];
64 MM.copy_physical_page(*physical_page, page_buffer);
65
66 TRY(m_inode->write_bytes(page_index * PAGE_SIZE, PAGE_SIZE, UserOrKernelBuffer::for_kernel_buffer(page_buffer), nullptr));
67 }
68
69 return {};
70}
71
72}