Kernel/LibC: Implement {,f}statvfs

This commit is contained in:
Bananymous 2024-12-02 06:55:35 +02:00
parent ad1f175a39
commit a10ca47657
21 changed files with 173 additions and 5 deletions

View File

@ -11,6 +11,18 @@ namespace Kernel
class Ext2FS final : public FileSystem
{
public:
virtual unsigned long bsize() const override;
virtual unsigned long frsize() const override;
virtual fsblkcnt_t blocks() const override;
virtual fsblkcnt_t bfree() const override;
virtual fsblkcnt_t bavail() const override;
virtual fsfilcnt_t files() const override;
virtual fsfilcnt_t ffree() const override;
virtual fsfilcnt_t favail() const override;
virtual unsigned long fsid() const override;
virtual unsigned long flag() const override;
virtual unsigned long namemax() const override;
class BlockBufferWrapper
{
BAN_NON_COPYABLE(BlockBufferWrapper);

View File

@ -29,6 +29,8 @@ namespace Kernel
virtual dev_t dev() const override { return 0; }
virtual dev_t rdev() const override { return 0; }
virtual const FileSystem* filesystem() const override;
protected:
virtual BAN::ErrorOr<BAN::RefPtr<Inode>> find_inode_impl(BAN::StringView) override;
virtual BAN::ErrorOr<size_t> list_next_inodes_impl(off_t, struct dirent*, size_t) override;

View File

@ -20,6 +20,18 @@ namespace Kernel
};
public:
virtual unsigned long bsize() const override;
virtual unsigned long frsize() const override;
virtual fsblkcnt_t blocks() const override;
virtual fsblkcnt_t bfree() const override;
virtual fsblkcnt_t bavail() const override;
virtual fsfilcnt_t files() const override;
virtual fsfilcnt_t ffree() const override;
virtual fsfilcnt_t favail() const override;
virtual unsigned long fsid() const override;
virtual unsigned long flag() const override;
virtual unsigned long namemax() const override;
static BAN::ErrorOr<bool> probe(BAN::RefPtr<BlockDevice>);
static BAN::ErrorOr<BAN::RefPtr<FATFS>> create(BAN::RefPtr<BlockDevice>);
@ -45,13 +57,15 @@ namespace Kernel
// TODO: These probably should be constant variables
uint32_t root_sector_count() const { return BAN::Math::div_round_up<uint32_t>(m_bpb.root_entry_count * 32, m_bpb.bytes_per_sector); }
uint32_t fat_sector_count() const { return m_bpb.fat_size16 ? m_bpb.fat_size16 : m_bpb.ext_32.fat_size32; }
uint32_t fat_size() const { return m_bpb.fat_size16 ? m_bpb.fat_size16 : m_bpb.ext_32.fat_size32; }
uint32_t total_sector_count() const { return m_bpb.total_sectors16 ? m_bpb.total_sectors16 : m_bpb.total_sectors32; }
uint32_t data_sector_count() const { return total_sector_count() - (m_bpb.reserved_sector_count + (m_bpb.number_of_fats * fat_sector_count()) + root_sector_count()); }
uint32_t data_sector_count() const { return total_sector_count() - (m_bpb.reserved_sector_count + (m_bpb.number_of_fats * fat_size()) + root_sector_count()); }
uint32_t cluster_count() const { return data_sector_count() / m_bpb.sectors_per_cluster; }
uint32_t first_data_sector() const { return m_bpb.reserved_sector_count + (m_bpb.number_of_fats * fat_sector_count()) + root_sector_count(); }
uint32_t first_data_sector() const { return m_bpb.reserved_sector_count + (m_bpb.number_of_fats * fat_size()) + root_sector_count(); }
uint32_t first_fat_sector() const { return m_bpb.reserved_sector_count; }
uint8_t bits_per_fat_entry() const { return static_cast<uint8_t>(m_type); }
private:
BAN::RefPtr<BlockDevice> m_block_device;
BAN::RefPtr<FATInode> m_root_inode;

View File

@ -29,6 +29,8 @@ namespace Kernel
virtual dev_t dev() const override { return 0; }
virtual dev_t rdev() const override { return 0; }
virtual const FileSystem* filesystem() const override;
const FAT::DirectoryEntry& entry() const { return m_entry; }
protected:

View File

@ -9,6 +9,18 @@ namespace Kernel
class FileSystem : public BAN::RefCounted<FileSystem>
{
public:
virtual unsigned long bsize() const = 0;
virtual unsigned long frsize() const = 0;
virtual fsblkcnt_t blocks() const = 0;
virtual fsblkcnt_t bfree() const = 0;
virtual fsblkcnt_t bavail() const = 0;
virtual fsfilcnt_t files() const = 0;
virtual fsfilcnt_t ffree() const = 0;
virtual fsfilcnt_t favail() const = 0;
virtual unsigned long fsid() const = 0;
virtual unsigned long flag() const = 0;
virtual unsigned long namemax() const = 0;
virtual ~FileSystem() {}
static BAN::ErrorOr<BAN::RefPtr<FileSystem>> from_block_device(BAN::RefPtr<BlockDevice>);

View File

@ -19,6 +19,8 @@
namespace Kernel
{
class FileSystem;
class FileBackedRegion;
class SharedFileData;
@ -86,6 +88,8 @@ namespace Kernel
virtual bool is_pipe() const { return false; }
virtual bool is_tty() const { return false; }
virtual const FileSystem* filesystem() const = 0;
// Directory API
BAN::ErrorOr<BAN::RefPtr<Inode>> find_inode(BAN::StringView);
BAN::ErrorOr<size_t> list_next_inodes(off_t, struct dirent* list, size_t list_size);

View File

@ -30,6 +30,8 @@ namespace Kernel
virtual dev_t dev() const override { return 0; } // FIXME
virtual dev_t rdev() const override { return 0; } // FIXME
virtual const FileSystem* filesystem() const override { return nullptr; }
protected:
virtual BAN::ErrorOr<size_t> read_impl(off_t, BAN::ByteSpan) override;
virtual BAN::ErrorOr<size_t> write_impl(off_t, BAN::ConstByteSpan) override;

View File

@ -44,6 +44,8 @@ namespace Kernel
dev_t dev() const final override { ASSERT_NOT_REACHED(); }
dev_t rdev() const final override { ASSERT_NOT_REACHED(); }
const FileSystem* filesystem() const final override { return nullptr; }
protected:
Socket(const Info& info)
: m_info(info)

View File

@ -40,6 +40,19 @@ namespace Kernel
static constexpr size_t no_page_limit = SIZE_MAX;
public:
// FIXME: basically all of these :)
virtual unsigned long bsize() const override { return PAGE_SIZE; }
virtual unsigned long frsize() const override { return PAGE_SIZE; }
virtual fsblkcnt_t blocks() const override { return m_max_pages; }
virtual fsblkcnt_t bfree() const override { return m_max_pages - m_used_pages; }
virtual fsblkcnt_t bavail() const override { return m_max_pages - m_used_pages; }
virtual fsfilcnt_t files() const override { return PAGE_SIZE * blocks() / sizeof(TmpDirectoryEntry); }
virtual fsfilcnt_t ffree() const override { return PAGE_SIZE * bfree() / sizeof(TmpDirectoryEntry); }
virtual fsfilcnt_t favail() const override { return PAGE_SIZE * bavail() / sizeof(TmpDirectoryEntry); }
virtual unsigned long fsid() const override { return reinterpret_cast<uintptr_t>(this); }
virtual unsigned long flag() const override { return 0; }
virtual unsigned long namemax() const override { return PAGE_SIZE; }
static BAN::ErrorOr<TmpFileSystem*> create(size_t max_pages, mode_t, uid_t, gid_t);
~TmpFileSystem();

View File

@ -42,6 +42,8 @@ namespace Kernel
static BAN::ErrorOr<BAN::RefPtr<TmpInode>> create_from_existing(TmpFileSystem&, ino_t, const TmpInodeInfo&);
~TmpInode();
virtual const FileSystem* filesystem() const override;
protected:
TmpInode(TmpFileSystem&, ino_t, const TmpInodeInfo&);

View File

@ -8,9 +8,22 @@
namespace Kernel
{
class VirtualFileSystem : public FileSystem
class VirtualFileSystem final : public FileSystem
{
public:
virtual unsigned long bsize() const override { return 0; }
virtual unsigned long frsize() const override { return 0; }
virtual fsblkcnt_t blocks() const override { return 0; }
virtual fsblkcnt_t bfree() const override { return 0; }
virtual fsblkcnt_t bavail() const override { return 0; }
virtual fsfilcnt_t files() const override { return 0; }
virtual fsfilcnt_t ffree() const override { return 0; }
virtual fsfilcnt_t favail() const override { return 0; }
virtual unsigned long fsid() const override { return 0; }
virtual unsigned long flag() const override { return 0; }
virtual unsigned long namemax() const override { return 0; }
static void initialize(BAN::StringView);
static VirtualFileSystem& get();

View File

@ -19,6 +19,7 @@
#include <sys/mman.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <sys/statvfs.h>
#include <sys/time.h>
#include <termios.h>
@ -147,6 +148,7 @@ namespace Kernel
BAN::ErrorOr<long> sys_fsync(int fd);
BAN::ErrorOr<long> sys_fstatat(int fd, const char* path, struct stat* buf, int flag);
BAN::ErrorOr<long> sys_fstatvfsat(int fd, const char* path, struct statvfs* buf);
BAN::ErrorOr<long> sys_realpath(const char* path, char* buffer);

View File

@ -32,6 +32,18 @@ namespace Kernel
return superblock.magic == Ext2::Enum::SUPER_MAGIC;
}
unsigned long Ext2FS::bsize() const { return block_size(); }
unsigned long Ext2FS::frsize() const { return block_size(); }
fsblkcnt_t Ext2FS::blocks() const { return m_superblock.blocks_count; }
fsblkcnt_t Ext2FS::bfree() const { return m_superblock.free_blocks_count; }
fsblkcnt_t Ext2FS::bavail() const { return m_superblock.free_blocks_count; } // FIXME
fsfilcnt_t Ext2FS::files() const { return m_superblock.inodes_count; }
fsfilcnt_t Ext2FS::ffree() const { return m_superblock.free_inodes_count; }
fsfilcnt_t Ext2FS::favail() const { return m_superblock.free_inodes_count; } // FIXME
unsigned long Ext2FS::fsid() const { return *reinterpret_cast<const unsigned long*>(m_superblock.uuid); } // FIXME?
unsigned long Ext2FS::flag() const { return 0; }
unsigned long Ext2FS::namemax() const { return 0xFF; }
BAN::ErrorOr<BAN::RefPtr<Ext2FS>> Ext2FS::create(BAN::RefPtr<BlockDevice> block_device)
{
auto ext2fs = TRY(BAN::RefPtr<Ext2FS>::create(block_device));

View File

@ -47,6 +47,11 @@ namespace Kernel
dwarnln("Could not cleanup inode from FS: {}", ret.error());
}
const FileSystem* Ext2Inode::filesystem() const
{
return &m_fs;
}
BAN::ErrorOr<BAN::Optional<uint32_t>> Ext2Inode::block_from_indirect_block(uint32_t block, uint32_t index, uint32_t depth)
{
if (block == 0)

View File

@ -64,6 +64,18 @@ namespace Kernel
return validate_bpb(bpb_span.as<const FAT::BPB>());
}
unsigned long FATFS::bsize() const { return m_bpb.bytes_per_sector; }
unsigned long FATFS::frsize() const { return m_bpb.bytes_per_sector; }
fsblkcnt_t FATFS::blocks() const { return data_sector_count(); }
fsblkcnt_t FATFS::bfree() const { return 0; } // FIXME
fsblkcnt_t FATFS::bavail() const { return 0; } // FIXME
fsfilcnt_t FATFS::files() const { return m_bpb.number_of_fats * fat_size() * 8 / bits_per_fat_entry(); }
fsfilcnt_t FATFS::ffree() const { return 0; } // FIXME
fsfilcnt_t FATFS::favail() const { return 0; } // FIXME
unsigned long FATFS::fsid() const { return m_type == Type::FAT32 ? m_bpb.ext_32.volume_id : m_bpb.ext_12_16.volume_id; }
unsigned long FATFS::flag() const { return 0; }
unsigned long FATFS::namemax() const { return 255; }
BAN::ErrorOr<BAN::RefPtr<FATFS>> FATFS::create(BAN::RefPtr<BlockDevice> block_device)
{
// support only block devices with sectors at least 512 bytes
@ -226,7 +238,7 @@ namespace Kernel
{
if (index >= root_sector_count())
return BAN::Error::from_errno(ENOENT);
const uint32_t first_root_sector = m_bpb.reserved_sector_count + (m_bpb.number_of_fats * fat_sector_count());
const uint32_t first_root_sector = m_bpb.reserved_sector_count + (m_bpb.number_of_fats * fat_size());
TRY(m_block_device->read_blocks(first_root_sector + index, 1, buffer));
return {};
}

View File

@ -46,6 +46,11 @@ namespace Kernel
return timespec { .tv_sec = epoch, .tv_nsec = 0 };
}
const FileSystem* FATInode::filesystem() const
{
return &m_fs;
}
BAN::ErrorOr<void> FATInode::for_each_directory_entry(BAN::ConstByteSpan entry_span, BAN::Function<BAN::Iteration(const FAT::DirectoryEntry&)> callback)
{
ASSERT(mode().ifdir());

View File

@ -41,6 +41,11 @@ namespace Kernel
/* GENERAL INODE */
const FileSystem* TmpInode::filesystem() const
{
return &m_fs;
}
dev_t TmpInode::dev() const
{
return m_fs.dev();

View File

@ -1496,6 +1496,35 @@ namespace Kernel
return 0;
}
BAN::ErrorOr<long> Process::sys_fstatvfsat(int fd, const char* path, struct statvfs* buf)
{
LockGuard _(m_process_lock);
TRY(validate_pointer_access(buf, sizeof(struct statvfs), true));
auto inode = TRY(find_file(fd, path, 0)).inode;
auto* fs = inode->filesystem();
if (fs == nullptr)
{
ASSERT(inode->mode().ifsock() || inode->mode().ififo());
dwarnln("TODO: fstatvfs on sockets or pipe?");
return BAN::Error::from_errno(EINVAL);
}
buf->f_bsize = fs->bsize();
buf->f_frsize = fs->frsize();
buf->f_blocks = fs->blocks();
buf->f_bfree = fs->bfree();
buf->f_bavail = fs->bavail();
buf->f_files = fs->files();
buf->f_ffree = fs->ffree();
buf->f_favail = fs->favail();
buf->f_fsid = fs->fsid();
buf->f_flag = fs->flag();
buf->f_namemax = fs->namemax();
return 0;
}
BAN::ErrorOr<long> Process::sys_realpath(const char* path, char* buffer)
{
LockGuard _(m_process_lock);

View File

@ -32,6 +32,7 @@ set(LIBC_SOURCES
sys/select.cpp
sys/socket.cpp
sys/stat.cpp
sys/statvfs.cpp
sys/time.cpp
sys/utsname.cpp
sys/wait.cpp

View File

@ -48,6 +48,7 @@ __BEGIN_DECLS
O(SYS_FCNTL, fcntl) \
O(SYS_NANOSLEEP, nanosleep) \
O(SYS_FSTATAT, fstatat) \
O(SYS_FSTATVFSAT, fstatvfsat) \
O(SYS_SYNC, sync) \
O(SYS_MMAP, mmap) \
O(SYS_MUNMAP, munmap) \

View File

@ -0,0 +1,18 @@
#include <fcntl.h>
#include <sys/statvfs.h>
#include <sys/syscall.h>
static int fstatvfsat(int fildes, const char* path, struct statvfs* buf)
{
return syscall(SYS_FSTATVFSAT, fildes, path, buf);
}
int fstatvfs(int fildes, struct statvfs* buf)
{
return fstatvfsat(fildes, nullptr, buf);
}
int statvfs(const char* __restrict path, struct statvfs* __restrict buf)
{
return fstatvfsat(AT_FDCWD, path, buf);
}