From e0d712c6f7525f0872e161ab6f22bb31b49b49ec Mon Sep 17 00:00:00 2001 From: Liav A Date: Sat, 14 Aug 2021 05:04:56 +0300 Subject: [PATCH] Kernel+SystemServer: Defer creation of device nodes to userspace Don't create these device nodes in the Kernel, so we essentially enforce userspace (SystemServer) to take control of this operation and to decide how to create these device nodes. This makes the DevFS to resemble linux devtmpfs, and allows us to remove a bunch of unneeded overriding implementations of device name creation in the Kernel. --- Kernel/FileSystem/DevFS.cpp | 83 ++++++++++++---------- Kernel/FileSystem/DevFS.h | 13 ++-- Kernel/FileSystem/InodeMetadata.h | 2 + Kernel/FileSystem/OpenFileDescription.cpp | 5 ++ Kernel/FileSystem/OpenFileDescription.h | 1 + Kernel/FileSystem/VirtualFileSystem.cpp | 1 + Userland/Services/SystemServer/main.cpp | 84 +++++++++++++++++++++++ 7 files changed, 144 insertions(+), 45 deletions(-) diff --git a/Kernel/FileSystem/DevFS.cpp b/Kernel/FileSystem/DevFS.cpp index c253bb77b22..882c5e45321 100644 --- a/Kernel/FileSystem/DevFS.cpp +++ b/Kernel/FileSystem/DevFS.cpp @@ -19,15 +19,6 @@ DevFS::DevFS() { } -void DevFS::notify_new_device(Device& device) -{ - // FIXME: Handle KString allocation failure. - auto name = KString::try_create(device.device_name()).release_value(); - MutexLocker locker(m_lock); - auto new_device_inode = adopt_ref(*new DevFSDeviceInode(*this, device, move(name))); - m_root_inode->m_nodes.append(new_device_inode); -} - size_t DevFS::allocate_inode_index() { MutexLocker locker(m_lock); @@ -36,11 +27,6 @@ size_t DevFS::allocate_inode_index() return 1 + m_next_inode_index.value(); } -void DevFS::notify_device_removal(Device&) -{ - TODO(); -} - DevFS::~DevFS() { } @@ -48,12 +34,6 @@ DevFS::~DevFS() KResult DevFS::initialize() { m_root_inode = TRY(adopt_nonnull_ref_or_enomem(new (nothrow) DevFSRootDirectoryInode(*this))); - Device::for_each([&](Device& device) { - // FIXME: Find a better way to not add MasterPTYs or SlavePTYs! - if (device.is_master_pty() || (device.is_character_device() && device.major() == 201)) - return; - notify_new_device(device); - }); return KSuccess; } @@ -214,7 +194,7 @@ KResultOr> DevFSRootDirectoryInode::lookup(StringView name) } return ENOENT; } -KResultOr> DevFSRootDirectoryInode::create_child(StringView name, mode_t mode, dev_t, UserID, GroupID) +KResultOr> DevFSRootDirectoryInode::create_child(StringView name, mode_t mode, dev_t device_mode, UserID, GroupID) { MutexLocker locker(fs().m_lock); @@ -232,6 +212,15 @@ KResultOr> DevFSRootDirectoryInode::create_child(StringView m_nodes.append(*new_directory_inode); return new_directory_inode; } + if (metadata.is_device()) { + auto name_kstring = TRY(KString::try_create(name)); + unsigned major = major_from_encoded_device(device_mode); + unsigned minor = minor_from_encoded_device(device_mode); + auto new_device_inode = TRY(adopt_nonnull_ref_or_enomem(new (nothrow) DevFSDeviceInode(fs(), major, minor, is_block_device(mode), move(name_kstring)))); + TRY(new_device_inode->chmod(mode)); + m_nodes.append(*new_device_inode); + return new_device_inode; + } if (metadata.is_symlink()) { auto name_kstring = TRY(KString::try_create(name)); auto new_link_inode = TRY(adopt_nonnull_ref_or_enomem(new (nothrow) DevFSLinkInode(fs(), move(name_kstring)))); @@ -256,10 +245,12 @@ InodeMetadata DevFSRootDirectoryInode::metadata() const return metadata; } -DevFSDeviceInode::DevFSDeviceInode(DevFS& fs, Device const& device, NonnullOwnPtr name) +DevFSDeviceInode::DevFSDeviceInode(DevFS& fs, unsigned major_number, unsigned minor_number, bool block_device, NonnullOwnPtr name) : DevFSInode(fs) - , m_attached_device(device) , m_name(move(name)) + , m_major_number(major_number) + , m_minor_number(minor_number) + , m_block_device(block_device) { } @@ -275,6 +266,16 @@ KResult DevFSDeviceInode::chown(UserID uid, GroupID gid) return KSuccess; } +KResult DevFSDeviceInode::chmod(mode_t mode) +{ + MutexLocker locker(m_inode_lock); + mode &= 0777; + if (m_required_mode == mode) + return KSuccess; + m_required_mode = mode; + return KSuccess; +} + StringView DevFSDeviceInode::name() const { return m_name->view(); @@ -284,12 +285,15 @@ KResultOr DevFSDeviceInode::read_bytes(off_t offset, size_t count, UserO { MutexLocker locker(m_inode_lock); VERIFY(!!description); - if (!m_attached_device->can_read(*description, offset)) - return 0; - auto nread = const_cast(*m_attached_device).read(*description, offset, buffer, count); - if (nread.is_error()) - return EIO; - return nread.value(); + RefPtr device = Device::get_device(m_major_number, m_minor_number); + if (!device) + return KResult(ENODEV); + if (!device->can_read(*description, offset)) + return KResult(ENOTIMPL); + auto result = const_cast(*device).read(*description, offset, buffer, count); + if (result.is_error()) + return result; + return result.value(); } InodeMetadata DevFSDeviceInode::metadata() const @@ -297,25 +301,28 @@ InodeMetadata DevFSDeviceInode::metadata() const MutexLocker locker(m_inode_lock); InodeMetadata metadata; metadata.inode = { fsid(), index() }; - metadata.mode = (m_attached_device->is_block_device() ? S_IFBLK : S_IFCHR) | m_attached_device->required_mode(); + metadata.mode = (m_block_device ? S_IFBLK : S_IFCHR) | m_required_mode; metadata.uid = m_uid; metadata.gid = m_gid; metadata.size = 0; metadata.mtime = mepoch; - metadata.major_device = m_attached_device->major(); - metadata.minor_device = m_attached_device->minor(); + metadata.major_device = m_major_number; + metadata.minor_device = m_minor_number; return metadata; } KResultOr DevFSDeviceInode::write_bytes(off_t offset, size_t count, const UserOrKernelBuffer& buffer, OpenFileDescription* description) { MutexLocker locker(m_inode_lock); VERIFY(!!description); - if (!m_attached_device->can_write(*description, offset)) - return 0; - auto nread = const_cast(*m_attached_device).write(*description, offset, buffer, count); - if (nread.is_error()) - return EIO; - return nread.value(); + RefPtr device = Device::get_device(m_major_number, m_minor_number); + if (!device) + return KResult(ENODEV); + if (!device->can_write(*description, offset)) + return KResult(ENOTIMPL); + auto result = const_cast(*device).write(*description, offset, buffer, count); + if (result.is_error()) + return result; + return result.value(); } DevFSPtsDirectoryInode::DevFSPtsDirectoryInode(DevFS& fs) diff --git a/Kernel/FileSystem/DevFS.h b/Kernel/FileSystem/DevFS.h index accae14ae55..c0860d403dc 100644 --- a/Kernel/FileSystem/DevFS.h +++ b/Kernel/FileSystem/DevFS.h @@ -24,10 +24,6 @@ public: virtual KResult initialize() override; virtual StringView class_name() const override { return "DevFS"sv; } - - void notify_new_device(Device&); - void notify_device_removal(Device&); - virtual Inode& root_inode() override; private: @@ -76,16 +72,19 @@ public: virtual ~DevFSDeviceInode() override; private: - DevFSDeviceInode(DevFS&, Device const&, NonnullOwnPtr name); + DevFSDeviceInode(DevFS&, unsigned, unsigned, bool, NonnullOwnPtr name); // ^Inode virtual KResultOr read_bytes(off_t, size_t, UserOrKernelBuffer& buffer, OpenFileDescription*) const override; virtual InodeMetadata metadata() const override; virtual KResultOr write_bytes(off_t, size_t, const UserOrKernelBuffer& buffer, OpenFileDescription*) override; virtual KResult chown(UserID, GroupID) override; + virtual KResult chmod(mode_t) override; - NonnullRefPtr m_attached_device; NonnullOwnPtr m_name; - + const unsigned m_major_number; + const unsigned m_minor_number; + const bool m_block_device; + mode_t m_required_mode; UserID m_uid { 0 }; GroupID m_gid { 0 }; }; diff --git a/Kernel/FileSystem/InodeMetadata.h b/Kernel/FileSystem/InodeMetadata.h index d71865d2fc8..03020413d77 100644 --- a/Kernel/FileSystem/InodeMetadata.h +++ b/Kernel/FileSystem/InodeMetadata.h @@ -19,6 +19,8 @@ constexpr u32 encoded_device(unsigned major, unsigned minor) { return (minor & 0xff) | (major << 8) | ((minor & ~0xff) << 12); } +static inline unsigned int major_from_encoded_device(dev_t dev) { return (dev & 0xfff00u) >> 8u; } +static inline unsigned int minor_from_encoded_device(dev_t dev) { return (dev & 0xffu) | ((dev >> 12u) & 0xfff00u); } inline bool is_directory(mode_t mode) { return (mode & S_IFMT) == S_IFDIR; } inline bool is_character_device(mode_t mode) { return (mode & S_IFMT) == S_IFCHR; } diff --git a/Kernel/FileSystem/OpenFileDescription.cpp b/Kernel/FileSystem/OpenFileDescription.cpp index 05803ecfc64..955b429fa56 100644 --- a/Kernel/FileSystem/OpenFileDescription.cpp +++ b/Kernel/FileSystem/OpenFileDescription.cpp @@ -71,6 +71,11 @@ KResult OpenFileDescription::attach() return m_file->attach(*this); } +void OpenFileDescription::set_original_custody(Badge, Custody& custody) +{ + m_custody = custody; +} + Thread::FileBlocker::BlockFlags OpenFileDescription::should_unblock(Thread::FileBlocker::BlockFlags block_flags) const { using BlockFlags = Thread::FileBlocker::BlockFlags; diff --git a/Kernel/FileSystem/OpenFileDescription.h b/Kernel/FileSystem/OpenFileDescription.h index 04c3c08e61c..2c3f1b1cfab 100644 --- a/Kernel/FileSystem/OpenFileDescription.h +++ b/Kernel/FileSystem/OpenFileDescription.h @@ -119,6 +119,7 @@ public: OwnPtr& data() { return m_data; } void set_original_inode(Badge, NonnullRefPtr&& inode) { m_inode = move(inode); } + void set_original_custody(Badge, Custody& custody); KResult truncate(u64); diff --git a/Kernel/FileSystem/VirtualFileSystem.cpp b/Kernel/FileSystem/VirtualFileSystem.cpp index 375355c313d..a019e157039 100644 --- a/Kernel/FileSystem/VirtualFileSystem.cpp +++ b/Kernel/FileSystem/VirtualFileSystem.cpp @@ -276,6 +276,7 @@ KResultOr> VirtualFileSystem::open(StringView } auto description = TRY(device->open(options)); description->set_original_inode({}, inode); + description->set_original_custody({}, custody); return description; } diff --git a/Userland/Services/SystemServer/main.cpp b/Userland/Services/SystemServer/main.cpp index e56c4c5af52..765e4454faf 100644 --- a/Userland/Services/SystemServer/main.cpp +++ b/Userland/Services/SystemServer/main.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -102,6 +103,61 @@ static void chown_all_matching_device_nodes(group* group, unsigned major_number) } } +constexpr unsigned encoded_device(unsigned major, unsigned minor) +{ + return (minor & 0xff) | (major << 8) | ((minor & ~0xff) << 12); +} + +static void populate_devfs() +{ + mode_t old_mask = umask(0); + if (auto rc = mknod("/dev/audio", 0220 | S_IFCHR, encoded_device(42, 42)); rc < 0) + VERIFY_NOT_REACHED(); + if (auto rc = mknod("/dev/console", 0666 | S_IFCHR, encoded_device(5, 1)); rc < 0) + VERIFY_NOT_REACHED(); + if (auto rc = mknod("/dev/fb0", 0666 | S_IFBLK, encoded_device(29, 0)); rc < 0) + VERIFY_NOT_REACHED(); + if (auto rc = mknod("/dev/full", 0660 | S_IFCHR, encoded_device(29, 0)); rc < 0) + VERIFY_NOT_REACHED(); + if (auto rc = mknod("/dev/hda", 0600 | S_IFBLK, encoded_device(3, 0)); rc < 0) + VERIFY_NOT_REACHED(); + if (auto rc = mknod("/dev/hvc0p0", 0666 | S_IFCHR, encoded_device(229, 0)); rc < 0) + VERIFY_NOT_REACHED(); + if (auto rc = mknod("/dev/hwrng", 0666 | S_IFCHR, encoded_device(10, 183)); rc < 0) + VERIFY_NOT_REACHED(); + if (auto rc = mknod("/dev/keyboard0", 0660 | S_IFCHR, encoded_device(85, 0)); rc < 0) + VERIFY_NOT_REACHED(); + if (auto rc = mknod("/dev/mem", 0660 | S_IFCHR, encoded_device(1, 1)); rc < 0) + VERIFY_NOT_REACHED(); + if (auto rc = mknod("/dev/mouse0", 0660 | S_IFCHR, encoded_device(10, 0)); rc < 0) + VERIFY_NOT_REACHED(); + if (auto rc = mknod("/dev/null", 0666 | S_IFCHR, encoded_device(1, 3)); rc < 0) + VERIFY_NOT_REACHED(); + if (auto rc = mknod("/dev/ptmx", 0666 | S_IFCHR, encoded_device(5, 2)); rc < 0) + VERIFY_NOT_REACHED(); + if (auto rc = mknod("/dev/random", 0666 | S_IFCHR, encoded_device(1, 8)); rc < 0) + VERIFY_NOT_REACHED(); + if (auto rc = mknod("/dev/tty0", 0620 | S_IFCHR, encoded_device(4, 0)); rc < 0) + VERIFY_NOT_REACHED(); + if (auto rc = mknod("/dev/tty1", 0620 | S_IFCHR, encoded_device(4, 1)); rc < 0) + VERIFY_NOT_REACHED(); + if (auto rc = mknod("/dev/tty2", 0620 | S_IFCHR, encoded_device(4, 2)); rc < 0) + VERIFY_NOT_REACHED(); + if (auto rc = mknod("/dev/tty3", 0620 | S_IFCHR, encoded_device(4, 3)); rc < 0) + VERIFY_NOT_REACHED(); + if (auto rc = mknod("/dev/ttyS0", 0620 | S_IFCHR, encoded_device(4, 64)); rc < 0) + VERIFY_NOT_REACHED(); + if (auto rc = mknod("/dev/ttyS1", 0620 | S_IFCHR, encoded_device(4, 65)); rc < 0) + VERIFY_NOT_REACHED(); + if (auto rc = mknod("/dev/ttyS2", 0620 | S_IFCHR, encoded_device(4, 66)); rc < 0) + VERIFY_NOT_REACHED(); + if (auto rc = mknod("/dev/ttyS3", 0666 | S_IFCHR, encoded_device(4, 67)); rc < 0) + VERIFY_NOT_REACHED(); + if (auto rc = mknod("/dev/zero", 0666 | S_IFCHR, encoded_device(1, 5)); rc < 0) + VERIFY_NOT_REACHED(); + umask(old_mask); +} + static void prepare_devfs() { // FIXME: Find a better way to all of this stuff, without hardcoding all of this! @@ -111,6 +167,8 @@ static void prepare_devfs() VERIFY_NOT_REACHED(); } + populate_devfs(); + rc = mount(-1, "/sys", "sys", 0); if (rc != 0) { VERIFY_NOT_REACHED(); @@ -162,6 +220,32 @@ static void prepare_devfs() VERIFY_NOT_REACHED(); } + // Note: We open the /dev/null device and set file descriptors 0, 1, 2 to it + // because otherwise these file descriptors won't have a custody, making + // the ProcFS file descriptor links (at /proc/PID/fd/{0,1,2}) to have an + // absolute path of "device:1,3" instead of something like "/dev/null". + // This affects also every other process that inherits the file descriptors + // from SystemServer, so it is important for other things (also for ProcFS + // tests that are running in CI mode). + + int stdin_new_fd = open("/dev/null", O_NONBLOCK); + if (stdin_new_fd < 0) { + VERIFY_NOT_REACHED(); + } + rc = dup2(stdin_new_fd, 0); + if (rc < 0) { + VERIFY_NOT_REACHED(); + } + + rc = dup2(stdin_new_fd, 1); + if (rc < 0) { + VERIFY_NOT_REACHED(); + } + rc = dup2(stdin_new_fd, 2); + if (rc < 0) { + VERIFY_NOT_REACHED(); + } + endgrent(); }