···11+/*
22+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
33+ * All rights reserved.
44+ *
55+ * Redistribution and use in source and binary forms, with or without
66+ * modification, are permitted provided that the following conditions are met:
77+ *
88+ * 1. Redistributions of source code must retain the above copyright notice, this
99+ * list of conditions and the following disclaimer.
1010+ *
1111+ * 2. Redistributions in binary form must reproduce the above copyright notice,
1212+ * this list of conditions and the following disclaimer in the documentation
1313+ * and/or other materials provided with the distribution.
1414+ *
1515+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
1616+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1717+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
1818+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
1919+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2020+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
2121+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
2222+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
2323+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2424+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2525+ */
2626+2727+#include <Kernel/FileSystem/Inode.h>
2828+#include <Kernel/VM/InodeVMObject.h>
2929+#include <Kernel/VM/MemoryManager.h>
3030+#include <Kernel/VM/Region.h>
3131+3232+namespace Kernel {
3333+3434+InodeVMObject::InodeVMObject(Inode& inode, size_t size)
3535+ : VMObject(size)
3636+ , m_inode(inode)
3737+ , m_dirty_pages(page_count(), false)
3838+{
3939+}
4040+4141+InodeVMObject::InodeVMObject(const InodeVMObject& other)
4242+ : VMObject(other)
4343+ , m_inode(other.m_inode)
4444+{
4545+}
4646+4747+InodeVMObject::~InodeVMObject()
4848+{
4949+}
5050+5151+size_t InodeVMObject::amount_clean() const
5252+{
5353+ size_t count = 0;
5454+ ASSERT(page_count() == (size_t)m_dirty_pages.size());
5555+ for (size_t i = 0; i < page_count(); ++i) {
5656+ if (!m_dirty_pages.get(i) && m_physical_pages[i])
5757+ ++count;
5858+ }
5959+ return count * PAGE_SIZE;
6060+}
6161+6262+size_t InodeVMObject::amount_dirty() const
6363+{
6464+ size_t count = 0;
6565+ for (size_t i = 0; i < m_dirty_pages.size(); ++i) {
6666+ if (m_dirty_pages.get(i))
6767+ ++count;
6868+ }
6969+ return count * PAGE_SIZE;
7070+}
7171+7272+void InodeVMObject::inode_size_changed(Badge<Inode>, size_t old_size, size_t new_size)
7373+{
7474+ dbg() << "VMObject::inode_size_changed: {" << m_inode->fsid() << ":" << m_inode->index() << "} " << old_size << " -> " << new_size;
7575+7676+ InterruptDisabler disabler;
7777+7878+ auto new_page_count = PAGE_ROUND_UP(new_size) / PAGE_SIZE;
7979+ m_physical_pages.resize(new_page_count);
8080+8181+ m_dirty_pages.grow(new_page_count, false);
8282+8383+ // FIXME: Consolidate with inode_contents_changed() so we only do a single walk.
8484+ for_each_region([](auto& region) {
8585+ region.remap();
8686+ });
8787+}
8888+8989+void InodeVMObject::inode_contents_changed(Badge<Inode>, off_t offset, ssize_t size, const u8* data)
9090+{
9191+ (void)size;
9292+ (void)data;
9393+ InterruptDisabler disabler;
9494+ ASSERT(offset >= 0);
9595+9696+ // FIXME: Only invalidate the parts that actually changed.
9797+ for (auto& physical_page : m_physical_pages)
9898+ physical_page = nullptr;
9999+100100+#if 0
101101+ size_t current_offset = offset;
102102+ size_t remaining_bytes = size;
103103+ const u8* data_ptr = data;
104104+105105+ auto to_page_index = [] (size_t offset) -> size_t {
106106+ return offset / PAGE_SIZE;
107107+ };
108108+109109+ if (current_offset & PAGE_MASK) {
110110+ size_t page_index = to_page_index(current_offset);
111111+ size_t bytes_to_copy = min(size, PAGE_SIZE - (current_offset & PAGE_MASK));
112112+ if (m_physical_pages[page_index]) {
113113+ auto* ptr = MM.quickmap_page(*m_physical_pages[page_index]);
114114+ memcpy(ptr, data_ptr, bytes_to_copy);
115115+ MM.unquickmap_page();
116116+ }
117117+ current_offset += bytes_to_copy;
118118+ data += bytes_to_copy;
119119+ remaining_bytes -= bytes_to_copy;
120120+ }
121121+122122+ for (size_t page_index = to_page_index(current_offset); page_index < m_physical_pages.size(); ++page_index) {
123123+ size_t bytes_to_copy = PAGE_SIZE - (current_offset & PAGE_MASK);
124124+ if (m_physical_pages[page_index]) {
125125+ auto* ptr = MM.quickmap_page(*m_physical_pages[page_index]);
126126+ memcpy(ptr, data_ptr, bytes_to_copy);
127127+ MM.unquickmap_page();
128128+ }
129129+ current_offset += bytes_to_copy;
130130+ data += bytes_to_copy;
131131+ }
132132+#endif
133133+134134+ // FIXME: Consolidate with inode_size_changed() so we only do a single walk.
135135+ for_each_region([](auto& region) {
136136+ region.remap();
137137+ });
138138+}
139139+140140+int InodeVMObject::release_all_clean_pages()
141141+{
142142+ LOCKER(m_paging_lock);
143143+ return release_all_clean_pages_impl();
144144+}
145145+146146+int InodeVMObject::release_all_clean_pages_impl()
147147+{
148148+ int count = 0;
149149+ InterruptDisabler disabler;
150150+ for (size_t i = 0; i < page_count(); ++i) {
151151+ if (!m_dirty_pages.get(i) && m_physical_pages[i]) {
152152+ m_physical_pages[i] = nullptr;
153153+ ++count;
154154+ }
155155+ }
156156+ for_each_region([](auto& region) {
157157+ region.remap();
158158+ });
159159+ return count;
160160+}
161161+162162+u32 InodeVMObject::writable_mappings() const
163163+{
164164+ u32 count = 0;
165165+ const_cast<InodeVMObject&>(*this).for_each_region([&](auto& region) {
166166+ if (region.is_writable())
167167+ ++count;
168168+ });
169169+ return count;
170170+}
171171+172172+u32 InodeVMObject::executable_mappings() const
173173+{
174174+ u32 count = 0;
175175+ const_cast<InodeVMObject&>(*this).for_each_region([&](auto& region) {
176176+ if (region.is_executable())
177177+ ++count;
178178+ });
179179+ return count;
180180+}
181181+182182+}
+69
Kernel/VM/InodeVMObject.h
···11+/*
22+ * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
33+ * All rights reserved.
44+ *
55+ * Redistribution and use in source and binary forms, with or without
66+ * modification, are permitted provided that the following conditions are met:
77+ *
88+ * 1. Redistributions of source code must retain the above copyright notice, this
99+ * list of conditions and the following disclaimer.
1010+ *
1111+ * 2. Redistributions in binary form must reproduce the above copyright notice,
1212+ * this list of conditions and the following disclaimer in the documentation
1313+ * and/or other materials provided with the distribution.
1414+ *
1515+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
1616+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1717+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
1818+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
1919+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2020+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
2121+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
2222+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
2323+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2424+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2525+ */
2626+2727+#pragma once
2828+2929+#include <AK/Bitmap.h>
3030+#include <Kernel/UnixTypes.h>
3131+#include <Kernel/VM/VMObject.h>
3232+3333+namespace Kernel {
3434+3535+class InodeVMObject : public VMObject {
3636+public:
3737+ virtual ~InodeVMObject() override;
3838+3939+ Inode& inode() { return *m_inode; }
4040+ const Inode& inode() const { return *m_inode; }
4141+4242+ void inode_contents_changed(Badge<Inode>, off_t, ssize_t, const u8*);
4343+ void inode_size_changed(Badge<Inode>, size_t old_size, size_t new_size);
4444+4545+ size_t amount_dirty() const;
4646+ size_t amount_clean() const;
4747+4848+ int release_all_clean_pages();
4949+5050+ u32 writable_mappings() const;
5151+ u32 executable_mappings() const;
5252+5353+protected:
5454+ explicit InodeVMObject(Inode&, size_t);
5555+ explicit InodeVMObject(const InodeVMObject&);
5656+5757+ InodeVMObject& operator=(const InodeVMObject&) = delete;
5858+ InodeVMObject& operator=(InodeVMObject&&) = delete;
5959+ InodeVMObject(InodeVMObject&&) = delete;
6060+6161+ virtual bool is_inode() const final { return true; }
6262+6363+ int release_all_clean_pages_impl();
6464+6565+ NonnullRefPtr<Inode> m_inode;
6666+ Bitmap m_dirty_pages;
6767+};
6868+6969+}
+56
Kernel/VM/PrivateInodeVMObject.cpp
···11+/*
22+ * Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
33+ * All rights reserved.
44+ *
55+ * Redistribution and use in source and binary forms, with or without
66+ * modification, are permitted provided that the following conditions are met:
77+ *
88+ * 1. Redistributions of source code must retain the above copyright notice, this
99+ * list of conditions and the following disclaimer.
1010+ *
1111+ * 2. Redistributions in binary form must reproduce the above copyright notice,
1212+ * this list of conditions and the following disclaimer in the documentation
1313+ * and/or other materials provided with the distribution.
1414+ *
1515+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
1616+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1717+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
1818+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
1919+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2020+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
2121+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
2222+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
2323+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2424+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2525+ */
2626+2727+#include <Kernel/FileSystem/Inode.h>
2828+#include <Kernel/VM/PrivateInodeVMObject.h>
2929+3030+namespace Kernel {
3131+3232+NonnullRefPtr<PrivateInodeVMObject> PrivateInodeVMObject::create_with_inode(Inode& inode)
3333+{
3434+ return adopt(*new PrivateInodeVMObject(inode, inode.size()));
3535+}
3636+3737+NonnullRefPtr<VMObject> PrivateInodeVMObject::clone()
3838+{
3939+ return adopt(*new PrivateInodeVMObject(*this));
4040+}
4141+4242+PrivateInodeVMObject::PrivateInodeVMObject(Inode& inode, size_t size)
4343+ : InodeVMObject(inode, size)
4444+{
4545+}
4646+4747+PrivateInodeVMObject::PrivateInodeVMObject(const PrivateInodeVMObject& other)
4848+ : InodeVMObject(other)
4949+{
5050+}
5151+5252+PrivateInodeVMObject::~PrivateInodeVMObject()
5353+{
5454+}
5555+5656+}
+51
Kernel/VM/PrivateInodeVMObject.h
···11+/*
22+ * Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
33+ * All rights reserved.
44+ *
55+ * Redistribution and use in source and binary forms, with or without
66+ * modification, are permitted provided that the following conditions are met:
77+ *
88+ * 1. Redistributions of source code must retain the above copyright notice, this
99+ * list of conditions and the following disclaimer.
1010+ *
1111+ * 2. Redistributions in binary form must reproduce the above copyright notice,
1212+ * this list of conditions and the following disclaimer in the documentation
1313+ * and/or other materials provided with the distribution.
1414+ *
1515+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
1616+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1717+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
1818+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
1919+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2020+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
2121+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
2222+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
2323+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2424+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2525+ */
2626+2727+#pragma once
2828+2929+#include <AK/Bitmap.h>
3030+#include <Kernel/UnixTypes.h>
3131+#include <Kernel/VM/InodeVMObject.h>
3232+3333+namespace Kernel {
3434+3535+class PrivateInodeVMObject final : public InodeVMObject {
3636+ AK_MAKE_NONMOVABLE(PrivateInodeVMObject);
3737+3838+public:
3939+ virtual ~PrivateInodeVMObject() override;
4040+4141+ static NonnullRefPtr<PrivateInodeVMObject> create_with_inode(Inode&);
4242+ virtual NonnullRefPtr<VMObject> clone() override;
4343+4444+private:
4545+ explicit PrivateInodeVMObject(Inode&, size_t);
4646+ explicit PrivateInodeVMObject(const PrivateInodeVMObject&);
4747+4848+ PrivateInodeVMObject& operator=(const PrivateInodeVMObject&) = delete;
4949+};
5050+5151+}