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.
This commit is contained in:
Jesse Buhagiar 2019-08-11 23:56:39 +10:00 committed by Andreas Kling
parent f7251c74a9
commit bc22456f89
Notes: sideshowbarker 2024-07-19 12:40:05 +09:00
13 changed files with 98 additions and 3 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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
Userland/umount.cpp Normal file
View File

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