Kernel: mount system call (#396)

It is now possible to mount ext2 `DiskDevice` devices under Serenity on
any folder in the root filesystem. Currently any user can do this with
any permissions. There's a fair amount of assumptions made here too,
that might not be too good, but can be worked on in the future. This is
a good start to allow more dynamic operation under the OS itself.

It is also currently impossible to unmount and such, and devices will
fail to mount in Linux as the FS 'needs to be cleaned'. I'll work on
getting `umount` done ASAP to rectify this (as well as working on less
assumption-making in the mount syscall. We don't want to just be able
to mount DiskDevices!). This could probably be fixed with some `-t`
flag or something similar.
This commit is contained in:
Jesse 2019-08-02 23:18:47 +10:00 committed by Andreas Kling
parent 3f91d2d0cc
commit 401c87a0cc
Notes: sideshowbarker 2024-07-19 12:56:25 +09:00
17 changed files with 123 additions and 14 deletions

View File

@ -25,6 +25,7 @@ public:
uid_t gid() const { return m_gid; }
virtual bool is_device() const override { return true; }
virtual bool is_disk_device() const { return false; }
protected:
Device(unsigned major, unsigned minor);

View File

@ -1,6 +1,7 @@
#include <Kernel/Devices/DiskDevice.h>
DiskDevice::DiskDevice()
DiskDevice::DiskDevice(int major, int minor)
: BlockDevice(major, minor)
{
}

View File

@ -2,11 +2,12 @@
#include <AK/RefCounted.h>
#include <AK/Types.h>
#include <Kernel/Devices/BlockDevice.h>
// FIXME: Support 64-bit DiskOffset
typedef u32 DiskOffset;
class DiskDevice : public RefCounted<DiskDevice> {
class DiskDevice : public BlockDevice {
public:
virtual ~DiskDevice();
@ -20,6 +21,8 @@ public:
virtual bool read_blocks(unsigned index, u16 count, u8*) = 0;
virtual bool write_blocks(unsigned index, u16 count, const u8*) = 0;
virtual bool is_disk_device() const override { return true; };
protected:
DiskDevice();
DiskDevice(int major, int minor);
};

View File

@ -8,7 +8,8 @@ NonnullRefPtr<DiskPartition> DiskPartition::create(NonnullRefPtr<DiskDevice> dev
}
DiskPartition::DiskPartition(NonnullRefPtr<DiskDevice> device, unsigned block_offset)
: m_device(move(device))
: DiskDevice(100, 0)
, m_device(move(device))
, m_block_offset(block_offset)
{
}

View File

@ -14,6 +14,12 @@ public:
virtual bool read_blocks(unsigned index, u16 count, u8*) override;
virtual bool write_blocks(unsigned index, u16 count, const u8*) override;
// ^BlockDevice
virtual ssize_t read(FileDescription&, u8*, ssize_t) override { return 0; }
virtual bool can_read(FileDescription&) const override { return true; }
virtual ssize_t write(FileDescription&, const u8*, ssize_t) override { return 0; }
virtual bool can_write(FileDescription&) const override { return true; }
private:
virtual const char* class_name() const override;

View File

@ -84,6 +84,7 @@ const char* FloppyDiskDevice::class_name() const
FloppyDiskDevice::FloppyDiskDevice(FloppyDiskDevice::DriveType type)
: IRQHandler(IRQ_FLOPPY_DRIVE)
, DiskDevice(89, (type == FloppyDiskDevice::DriveType::Master) ? 0 : 1)
, m_io_base_addr((type == FloppyDiskDevice::DriveType::Master) ? 0x3F0 : 0x370)
{
initialize();

View File

@ -132,7 +132,7 @@ private:
};
public:
static NonnullRefPtr<FloppyDiskDevice> create(DriveType type);
static NonnullRefPtr<FloppyDiskDevice> create(DriveType);
virtual ~FloppyDiskDevice() override;
// ^DiskDevice
@ -142,6 +142,12 @@ public:
virtual bool read_blocks(unsigned index, u16 count, u8*) override;
virtual bool write_blocks(unsigned index, u16 count, const u8*) override;
// ^BlockDevice
virtual ssize_t read(FileDescription&, u8*, ssize_t) override { return 0; }
virtual bool can_read(FileDescription&) const override { return true; }
virtual ssize_t write(FileDescription&, const u8*, ssize_t) override { return 0; }
virtual bool can_write(FileDescription&) const override { return true; }
protected:
explicit FloppyDiskDevice(DriveType);

View File

@ -236,11 +236,12 @@ void PATAChannel::detect_disks()
heads,
spt);
int major = (m_channel_number == 0) ? 3 : 4;
if (i == 0) {
m_master = PATADiskDevice::create(*this, PATADiskDevice::DriveType::Master);
m_master = PATADiskDevice::create(*this, PATADiskDevice::DriveType::Master, major, 0);
m_master->set_drive_geometry(cyls, heads, spt);
} else {
m_slave = PATADiskDevice::create(*this, PATADiskDevice::DriveType::Slave);
m_slave = PATADiskDevice::create(*this, PATADiskDevice::DriveType::Slave, major, 1);
m_slave->set_drive_geometry(cyls, heads, spt);
}
}

View File

@ -78,13 +78,14 @@
#define ATA_REG_ALTSTATUS 0x0C
#define ATA_REG_DEVADDRESS 0x0D
NonnullRefPtr<PATADiskDevice> PATADiskDevice::create(PATAChannel& channel, DriveType type)
NonnullRefPtr<PATADiskDevice> PATADiskDevice::create(PATAChannel& channel, DriveType type, int major, int minor)
{
return adopt(*new PATADiskDevice(channel, type));
return adopt(*new PATADiskDevice(channel, type, major, minor));
}
PATADiskDevice::PATADiskDevice(PATAChannel& channel, DriveType type)
: m_drive_type(type)
PATADiskDevice::PATADiskDevice(PATAChannel& channel, DriveType type, int major, int minor)
: DiskDevice(major, minor)
, m_drive_type(type)
, m_channel(channel)
{
}

View File

@ -26,7 +26,7 @@ public:
};
public:
static NonnullRefPtr<PATADiskDevice> create(PATAChannel&, DriveType);
static NonnullRefPtr<PATADiskDevice> create(PATAChannel&, DriveType, int major, int minor);
virtual ~PATADiskDevice() override;
// ^DiskDevice
@ -38,8 +38,14 @@ public:
void set_drive_geometry(u16, u16, u16);
// ^BlockDevice
virtual ssize_t read(FileDescription&, u8*, ssize_t) override { return 0; }
virtual bool can_read(FileDescription&) const override { return true; }
virtual ssize_t write(FileDescription&, const u8*, ssize_t) override { return 0; }
virtual bool can_write(FileDescription&) const override { return true; }
protected:
explicit PATADiskDevice(PATAChannel&, DriveType);
explicit PATADiskDevice(PATAChannel&, DriveType, int, int);
private:
// ^DiskDevice

View File

@ -8,6 +8,7 @@
#include <Kernel/Arch/i386/PIT.h>
#include <Kernel/Devices/NullDevice.h>
#include <Kernel/FileSystem/Custody.h>
#include <Kernel/FileSystem/Ext2FileSystem.h>
#include <Kernel/FileSystem/FIFO.h>
#include <Kernel/FileSystem/FileDescription.h>
#include <Kernel/FileSystem/InodeWatcher.h>
@ -1900,7 +1901,7 @@ int Process::sys$poll(pollfd* fds, int nfds, int timeout)
dbgprintf("%s<%u> polling on (read:%u, write:%u), timeout=%d\n", name().characters(), pid(), rfds.size(), wfds.size(), timeout);
#endif
if (has_timeout|| timeout < 0) {
if (has_timeout || timeout < 0) {
if (current->block<Thread::SelectBlocker>(actual_timeout, has_timeout, rfds, wfds, Thread::SelectBlocker::FDVector()) == Thread::BlockResult::InterruptedBySignal)
return -EINTR;
}
@ -2726,6 +2727,47 @@ int Process::sys$reboot()
return ESUCCESS;
}
int Process::sys$mount(const char* device, const char* mountpoint)
{
dbgprintf("mount: device = %s mountpoint = %s\n", device, mountpoint);
if (!validate_read_str(device) || !validate_read_str(mountpoint))
return -EFAULT;
// Let's do a stat to get some information about the device..
// Let's use lstat so we can convert devname into a major/minor device pair!
struct stat st;
int rc = sys$stat(device, &st);
if (rc < 0) {
dbgprintf("mount: call to sys$stat failed!\n");
return -ENODEV;
}
int major = (st.st_rdev & 0xfff00u) >> 8u;
int minor = (st.st_rdev & 0xffu) | ((st.st_rdev >> 12u) & 0xfff00u);
auto* dev = VFS::the().get_device(major, minor);
auto* disk_device = static_cast<DiskDevice*>(dev);
dbgprintf("mount: attempting to mount %d,%d to %s...\n", major, minor, mountpoint);
// Do a quick check to make sure we're not passing nullptr to Ext2FS::create!
if (dev == nullptr)
return -ENODEV;
// We currently only support ext2. Sorry :^)
auto ext2fs = Ext2FS::create(*disk_device);
if (!ext2fs->initialize()) {
dbgprintf("mount: failed to create ext2fs!\n");
return -ENODEV; // Hmmm, this doesn't seem quite right....
}
// Let's mount the volume now
VFS::the().mount(ext2fs, mountpoint);
dbgprintf("mount: successfully mounted ext2 volume on %s to %s!\n", device, mountpoint);
return ESUCCESS;
}
ProcessTracer& Process::ensure_tracer()
{
if (!m_tracer)

View File

@ -183,6 +183,7 @@ public:
int sys$unlink(const char* pathname);
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$read_tsc(u32* lsw, u32* msw);
int sys$chmod(const char* pathname, mode_t);
int sys$fchmod(int fd, mode_t);

View File

@ -292,6 +292,8 @@ static u32 handle(RegisterDump& regs, u32 function, u32 arg1, u32 arg2, u32 arg3
return current->process().sys$halt();
break;
}
case Syscall::SC_mount:
return current->process().sys$mount((const char*)arg1, (const char*)arg2);
case Syscall::SC_reboot: {
return current->process().sys$reboot();
}

View File

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

View File

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

View File

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

29
Userland/mount.cpp Normal file
View File

@ -0,0 +1,29 @@
#include <LibCore/CArgsParser.h>
#include <stdio.h>
#include <unistd.h>
// This version of 'mount' must have the following arguments
// 'mount <device_path> <mount_point>
// It can currently only mount _physical_ devices found in /dev
//
// Currently, it is only possible to mount ext2 devices. Sorry! :^)
int main(int argc, char** argv)
{
CArgsParser args_parser("mount");
args_parser.add_arg("devname", "device path");
args_parser.add_arg("mountpoint", "mount point");
CArgsParserResult args = args_parser.parse(argc, argv);
if (argc == 3) {
// Let's use lstat so we can convert devname into a major/minor device pair!
if (mount(argv[1], argv[2]) < 0) {
perror("mount");
return 1;
}
} else {
args_parser.print_usage();
return 0;
}
return 0;
}