Pārlūkot izejas kodu

Kernel: Added unmount ability to VFS

It is now possible to unmount file systems from the VFS via `umount`.
It works via looking up the `fsid` of the filesystem from the `Inode`'s
metatdata so I'm not sure how fragile it is. It seems to work for now
though as something to get us going.
Jesse Buhagiar 6 gadi atpakaļ
vecāks
revīzija
bc22456f89

+ 13 - 0
Kernel/FileSystem/Ext2FileSystem.cpp

@@ -1395,3 +1395,16 @@ unsigned Ext2FS::free_inode_count() const
     LOCKER(m_lock);
     return super_block().s_free_inodes_count;
 }
+
+KResult Ext2FS::prepare_to_unmount() const
+{
+    LOCKER(m_lock); // Acquire lock for this FS
+    for (auto it = m_inode_cache.begin(); it != m_inode_cache.end(); ++it) {
+        if (it->value.ptr()->ref_count() > 1)
+            return KResult(-EBUSY);
+    }
+
+    dbg() << "here!";
+    m_inode_cache.clear();
+    return KSuccess;
+}

+ 2 - 0
Kernel/FileSystem/Ext2FileSystem.h

@@ -69,6 +69,8 @@ public:
     virtual unsigned total_inode_count() const override;
     virtual unsigned free_inode_count() const override;
 
+    virtual KResult prepare_to_unmount() const override;
+
 private:
     typedef unsigned BlockIndex;
     typedef unsigned GroupIndex;

+ 3 - 1
Kernel/FileSystem/FileSystem.h

@@ -8,8 +8,8 @@
 #include <AK/Function.h>
 #include <AK/HashMap.h>
 #include <AK/OwnPtr.h>
-#include <AK/RefPtr.h>
 #include <AK/RefCounted.h>
+#include <AK/RefPtr.h>
 #include <AK/WeakPtr.h>
 #include <AK/kstdio.h>
 #include <Kernel/Devices/DiskDevice.h>
@@ -45,6 +45,8 @@ public:
     virtual unsigned total_inode_count() const { return 0; }
     virtual unsigned free_inode_count() const { return 0; }
 
+    virtual KResult prepare_to_unmount() const { return KSuccess; }
+
     struct DirectoryEntry {
         DirectoryEntry(const char* name, InodeIdentifier, u8 file_type);
         DirectoryEntry(const char* name, int name_length, InodeIdentifier, u8 file_type);

+ 23 - 0
Kernel/FileSystem/VirtualFileSystem.cpp

@@ -49,6 +49,7 @@ KResult VFS::mount(NonnullRefPtr<FS>&& file_system, Custody& mount_point)
 
 KResult VFS::mount(NonnullRefPtr<FS>&& file_system, StringView path)
 {
+    LOCKER(m_lock);
     auto result = resolve_path(path, root_custody());
     if (result.is_error()) {
         dbg() << "VFS: mount can't resolve mount point '" << path << "'";
@@ -57,6 +58,28 @@ KResult VFS::mount(NonnullRefPtr<FS>&& file_system, StringView path)
     return mount(move(file_system), result.value());
 }
 
+KResult VFS::unmount(NonnullRefPtr<FS>&& file_system)
+{
+    LOCKER(m_lock);
+    dbg() << "VFS: unmount called with fsid " << file_system.ptr()->fsid();
+
+    for (auto i = 0; i < m_mounts.size(); i++) {
+        auto mount = m_mounts.at(i);
+        if (mount.guest_fs().fsid() == file_system.ptr()->fsid()) {
+            if (mount.guest_fs().prepare_to_unmount() != KSuccess) {
+                dbg() << "VFS: Failed to unmount! Device busy";
+                return KResult(-EBUSY);
+            }
+            dbg() << "VFS: found fs " << file_system.ptr()->fsid() << " at mount " << i << "! Unmounting...";
+            m_mounts.remove(i);
+            return KSuccess;
+        }
+    }
+
+    dbg() << "VFS: unmount unable to find fsid in m_mounts!";
+    return KResult(-ENODEV);
+}
+
 bool VFS::mount_root(NonnullRefPtr<FS>&& file_system)
 {
     if (m_root_inode) {

+ 3 - 0
Kernel/FileSystem/VirtualFileSystem.h

@@ -59,6 +59,7 @@ public:
     bool mount_root(NonnullRefPtr<FS>&&);
     KResult mount(NonnullRefPtr<FS>&&, StringView path);
     KResult mount(NonnullRefPtr<FS>&&, Custody& mount_point);
+    KResult unmount(NonnullRefPtr<FS>&&);
 
     KResultOr<NonnullRefPtr<FileDescription>> open(StringView path, int options, mode_t mode, Custody& base);
     KResultOr<NonnullRefPtr<FileDescription>> create(StringView path, int options, mode_t mode, Custody& parent_custody);
@@ -105,6 +106,8 @@ private:
     Mount* find_mount_for_host(InodeIdentifier);
     Mount* find_mount_for_guest(InodeIdentifier);
 
+    Lock m_lock { "VFSLock" };
+
     RefPtr<Inode> m_root_inode;
     NonnullOwnPtrVector<Mount> m_mounts;
     HashMap<u32, Device*> m_devices;

+ 19 - 0
Kernel/Process.cpp

@@ -2786,6 +2786,25 @@ int Process::sys$mount(const char* device_path, const char* mountpoint)
     return result;
 }
 
+int Process::sys$umount(const char* mountpoint)
+{
+    if (!is_superuser())
+        return -EPERM;
+
+    if (!validate_read_str(mountpoint))
+        return -EFAULT;
+
+    auto metadata_or_error = VFS::the().lookup_metadata(mountpoint, current_directory());
+    if (metadata_or_error.is_error())
+        return metadata_or_error.error();
+
+    auto fsid = metadata_or_error.value().inode.fsid();
+    auto fs = Ext2FS::from_fsid(fsid);
+    auto ret = VFS::the().unmount(*fs);
+
+    return ret;
+}
+
 ProcessTracer& Process::ensure_tracer()
 {
     if (!m_tracer)

+ 1 - 0
Kernel/Process.h

@@ -187,6 +187,7 @@ public:
     int sys$symlink(const char* target, const char* linkpath);
     int sys$rmdir(const char* pathname);
     int sys$mount(const char* device, const char* mountpoint);
+    int sys$umount(const char* mountpoint);
     int sys$read_tsc(u32* lsw, u32* msw);
     int sys$chmod(const char* pathname, mode_t);
     int sys$fchmod(int fd, mode_t);

+ 3 - 1
Kernel/Syscall.cpp

@@ -189,7 +189,7 @@ static u32 handle(RegisterDump& regs, u32 function, u32 arg1, u32 arg2, u32 arg3
     case Syscall::SC_sigprocmask:
         return current->process().sys$sigprocmask((int)arg1, (const sigset_t*)arg2, (sigset_t*)arg3);
     case Syscall::SC_pipe:
-        return current->process().sys$pipe((int*)arg1, (int) arg2);
+        return current->process().sys$pipe((int*)arg1, (int)arg2);
     case Syscall::SC_killpg:
         return current->process().sys$killpg((int)arg1, (int)arg2);
     case Syscall::SC_setuid:
@@ -297,6 +297,8 @@ static u32 handle(RegisterDump& regs, u32 function, u32 arg1, u32 arg2, u32 arg3
     case Syscall::SC_reboot: {
         return current->process().sys$reboot();
     }
+    case Syscall::SC_umount:
+        return current->process().sys$umount((const char*)arg1);
     case Syscall::SC_dump_backtrace:
         return current->process().sys$dump_backtrace();
     case Syscall::SC_watch_file:

+ 1 - 0
Kernel/Syscall.h

@@ -117,6 +117,7 @@ struct timeval;
     __ENUMERATE_SYSCALL(halt)                   \
     __ENUMERATE_SYSCALL(reboot)                 \
     __ENUMERATE_SYSCALL(mount)                  \
+    __ENUMERATE_SYSCALL(umount)                 \
     __ENUMERATE_SYSCALL(dump_backtrace)         \
     __ENUMERATE_SYSCALL(dbgputch)               \
     __ENUMERATE_SYSCALL(dbgputstr)              \

+ 1 - 1
Kernel/build-root-filesystem.sh

@@ -15,7 +15,7 @@ if [ $(id -u) != 0 ]; then
 fi
 
 echo -n "creating initial filesystem structure... "
-mkdir -p mnt/{bin,etc,proc,tmp}
+mkdir -p mnt/{bin,etc,proc,mnt,tmp}
 chmod 1777 mnt/tmp
 echo "done"
 

+ 6 - 0
Libraries/LibC/unistd.cpp

@@ -557,6 +557,12 @@ int mount(const char* device, const char* mountpoint)
     __RETURN_WITH_ERRNO(rc, rc, -1);
 }
 
+int umount(const char* mountpoint)
+{
+    int rc = syscall(SC_umount, mountpoint);
+    __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
 void dump_backtrace()
 {
     syscall(SC_dump_backtrace);

+ 1 - 0
Libraries/LibC/unistd.h

@@ -101,6 +101,7 @@ int ftruncate(int fd, off_t length);
 int halt();
 int reboot();
 int mount(const char* device, const char* mountpoint);
+int umount(const char* mountpoint);
 
 enum {
     _PC_NAME_MAX,

+ 22 - 0
Userland/umount.cpp

@@ -0,0 +1,22 @@
+#include <LibCore/CArgsParser.h>
+#include <stdio.h>
+#include <unistd.h>
+
+int main(int argc, char** argv)
+{
+    CArgsParser args_parser("umount");
+    args_parser.add_arg("mountpoint", "mount point");
+    CArgsParserResult args = args_parser.parse(argc, argv);
+
+    if (argc == 2) {
+        if (umount(argv[1]) < 0) {
+            perror("umount");
+            return 1;
+        }
+    } else {
+        args_parser.print_usage();
+        return 0;
+    }
+
+    return 0;
+}