Explorar o código

Kernel: Add a mode flag to sys$purge and allow purging clean inodes

Andreas Kling %!s(int64=5) %!d(string=hai) anos
pai
achega
1f31156173

+ 28 - 12
Kernel/Process.cpp

@@ -404,20 +404,36 @@ int Process::sys$madvise(void* address, size_t size, int advice)
     return -EINVAL;
     return -EINVAL;
 }
 }
 
 
-int Process::sys$purge()
+int Process::sys$purge(int mode)
 {
 {
-    NonnullRefPtrVector<PurgeableVMObject> vmobjects;
-    {
-        InterruptDisabler disabler;
-        MM.for_each_vmobject([&](auto& vmobject) {
-            if (vmobject.is_purgeable())
-                vmobjects.append(static_cast<PurgeableVMObject&>(vmobject));
-            return IterationDecision::Continue;
-        });
-    }
     int purged_page_count = 0;
     int purged_page_count = 0;
-    for (auto& vmobject : vmobjects) {
-        purged_page_count += vmobject.purge();
+    if (mode & PURGE_ALL_VOLATILE) {
+        NonnullRefPtrVector<PurgeableVMObject> vmobjects;
+        {
+            InterruptDisabler disabler;
+            MM.for_each_vmobject([&](auto& vmobject) {
+                if (vmobject.is_purgeable())
+                    vmobjects.append(static_cast<PurgeableVMObject&>(vmobject));
+                return IterationDecision::Continue;
+            });
+        }
+        for (auto& vmobject : vmobjects) {
+            purged_page_count += vmobject.purge();
+        }
+    }
+    if (mode & PURGE_ALL_CLEAN_INODE) {
+        NonnullRefPtrVector<InodeVMObject> vmobjects;
+        {
+            InterruptDisabler disabler;
+            MM.for_each_vmobject([&](auto& vmobject) {
+                if (vmobject.is_inode())
+                    vmobjects.append(static_cast<InodeVMObject&>(vmobject));
+                return IterationDecision::Continue;
+            });
+        }
+        for (auto& vmobject : vmobjects) {
+            purged_page_count += vmobject.release_all_clean_pages();
+        }
     }
     }
     return purged_page_count;
     return purged_page_count;
 }
 }

+ 1 - 1
Kernel/Process.h

@@ -142,7 +142,7 @@ public:
     int sys$set_mmap_name(void*, size_t, const char*);
     int sys$set_mmap_name(void*, size_t, const char*);
     int sys$mprotect(void*, size_t, int prot);
     int sys$mprotect(void*, size_t, int prot);
     int sys$madvise(void*, size_t, int advice);
     int sys$madvise(void*, size_t, int advice);
-    int sys$purge();
+    int sys$purge(int mode);
     int sys$select(const Syscall::SC_select_params*);
     int sys$select(const Syscall::SC_select_params*);
     int sys$poll(pollfd*, int nfds, int timeout);
     int sys$poll(pollfd*, int nfds, int timeout);
     ssize_t sys$get_dir_entries(int fd, void*, ssize_t);
     ssize_t sys$get_dir_entries(int fd, void*, ssize_t);

+ 2 - 0
Kernel/UnixTypes.h

@@ -467,3 +467,5 @@ struct ifreq {
 
 
 #define AT_FDCWD -100
 #define AT_FDCWD -100
 
 
+#define PURGE_ALL_VOLATILE 0x1
+#define PURGE_ALL_CLEAN_INODE 0x2

+ 24 - 1
Kernel/VM/InodeVMObject.cpp

@@ -39,7 +39,8 @@ InodeVMObject::~InodeVMObject()
 size_t InodeVMObject::amount_clean() const
 size_t InodeVMObject::amount_clean() const
 {
 {
     size_t count = 0;
     size_t count = 0;
-    for (int i = 0; i < m_dirty_pages.size(); ++i) {
+    ASSERT(page_count() == (size_t)m_dirty_pages.size());
+    for (size_t i = 0; i < page_count(); ++i) {
         if (!m_dirty_pages.get(i) && m_physical_pages[i])
         if (!m_dirty_pages.get(i) && m_physical_pages[i])
             ++count;
             ++count;
     }
     }
@@ -125,3 +126,25 @@ void InodeVMObject::inode_contents_changed(Badge<Inode>, off_t offset, ssize_t s
         region.remap();
         region.remap();
     });
     });
 }
 }
+
+int InodeVMObject::release_all_clean_pages()
+{
+    LOCKER(m_paging_lock);
+    return release_all_clean_pages_impl();
+}
+
+int InodeVMObject::release_all_clean_pages_impl()
+{
+    int count = 0;
+    InterruptDisabler disabler;
+    for (size_t i = 0; i < page_count(); ++i) {
+        if (!m_dirty_pages.get(i) && m_physical_pages[i]) {
+            m_physical_pages[i] = nullptr;
+            ++count;
+        }
+    }
+    for_each_region([](auto& region) {
+        region.remap();
+    });
+    return count;
+}

+ 4 - 0
Kernel/VM/InodeVMObject.h

@@ -19,6 +19,8 @@ public:
     size_t amount_dirty() const;
     size_t amount_dirty() const;
     size_t amount_clean() const;
     size_t amount_clean() const;
 
 
+    int release_all_clean_pages();
+
 private:
 private:
     explicit InodeVMObject(Inode&);
     explicit InodeVMObject(Inode&);
     explicit InodeVMObject(const InodeVMObject&);
     explicit InodeVMObject(const InodeVMObject&);
@@ -29,6 +31,8 @@ private:
 
 
     virtual bool is_inode() const override { return true; }
     virtual bool is_inode() const override { return true; }
 
 
+    int release_all_clean_pages_impl();
+
     NonnullRefPtr<Inode> m_inode;
     NonnullRefPtr<Inode> m_inode;
     Bitmap m_dirty_pages;
     Bitmap m_dirty_pages;
 };
 };

+ 4 - 0
Kernel/VM/Region.cpp

@@ -410,6 +410,10 @@ PageFaultResponse Region::handle_inode_fault(size_t page_index_in_region)
     LOCKER(vmobject().m_paging_lock);
     LOCKER(vmobject().m_paging_lock);
     cli();
     cli();
 
 
+#ifdef PAGE_FAULT_DEBUG
+    dbg() << *current << " inode fault in " << name() << " page index: " << page_index_in_region;
+#endif
+
     if (!vmobject_physical_page_entry.is_null()) {
     if (!vmobject_physical_page_entry.is_null()) {
 #ifdef PAGE_FAULT_DEBUG
 #ifdef PAGE_FAULT_DEBUG
         dbgprintf("MM: page_in_from_inode() but page already present. Fine with me!\n");
         dbgprintf("MM: page_in_from_inode() but page already present. Fine with me!\n");

+ 20 - 3
Userland/purge.cpp

@@ -1,9 +1,26 @@
-#include <stdio.h>
 #include <Kernel/Syscall.h>
 #include <Kernel/Syscall.h>
+#include <stdio.h>
+#include <string.h>
+
+#define PURGE_ALL_VOLATILE 0x1
+#define PURGE_ALL_CLEAN_INODE 0x2
 
 
-int main(int, char**)
+int main(int argc, char** argv)
 {
 {
-    int purged_page_count = syscall(SC_purge);
+    int mode = 0;
+    if (argc == 1) {
+        mode = PURGE_ALL_VOLATILE | PURGE_ALL_CLEAN_INODE;
+    } else {
+        if (!strcmp(argv[1], "-c")) {
+            mode = PURGE_ALL_CLEAN_INODE;
+        } else if (!strcmp(argv[1], "-v")) {
+            mode = PURGE_ALL_VOLATILE;
+        } else {
+            fprintf(stderr, "Unknown option: %s\n", argv[1]);
+            return 1;
+        }
+    }
+    int purged_page_count = syscall(SC_purge, mode);
     printf("Purged page count: %d\n", purged_page_count);
     printf("Purged page count: %d\n", purged_page_count);
     return 0;
     return 0;
 }
 }