forked from Bananymous/banan-os
Kernel/LibC: Implement fsync
This commit is contained in:
parent
cccb4e6d5e
commit
747c3b2a4b
|
@ -24,6 +24,8 @@ namespace Kernel
|
|||
|
||||
protected:
|
||||
Device(mode_t, uid_t, gid_t);
|
||||
|
||||
virtual BAN::ErrorOr<void> fsync_impl() final override { return BAN::Error::from_errno(EINVAL); }
|
||||
};
|
||||
|
||||
class BlockDevice : public Device
|
||||
|
@ -31,6 +33,7 @@ namespace Kernel
|
|||
public:
|
||||
virtual BAN::ErrorOr<void> read_blocks(uint64_t first_block, size_t block_count, BAN::ByteSpan) = 0;
|
||||
virtual BAN::ErrorOr<void> write_blocks(uint64_t first_block, size_t block_count, BAN::ConstByteSpan) = 0;
|
||||
virtual BAN::ErrorOr<void> sync_blocks(uint64_t block, size_t block_count) = 0;
|
||||
|
||||
virtual blksize_t blksize() const = 0;
|
||||
|
||||
|
|
|
@ -67,6 +67,7 @@ namespace Kernel
|
|||
BAN::ErrorOr<void> read_block(uint32_t, BlockBufferWrapper&);
|
||||
BAN::ErrorOr<void> write_block(uint32_t, const BlockBufferWrapper&);
|
||||
BAN::ErrorOr<void> sync_superblock();
|
||||
BAN::ErrorOr<void> sync_block(uint32_t block);
|
||||
|
||||
BlockBufferWrapper get_block_buffer();
|
||||
|
||||
|
|
|
@ -42,6 +42,7 @@ namespace Kernel
|
|||
virtual BAN::ErrorOr<size_t> write_impl(off_t, BAN::ConstByteSpan) override;
|
||||
virtual BAN::ErrorOr<void> truncate_impl(size_t) override;
|
||||
virtual BAN::ErrorOr<void> chmod_impl(mode_t) override;
|
||||
virtual BAN::ErrorOr<void> fsync_impl() override;
|
||||
|
||||
virtual bool can_read_impl() const override { return true; }
|
||||
virtual bool can_write_impl() const override { return true; }
|
||||
|
|
|
@ -42,6 +42,7 @@ namespace Kernel
|
|||
//virtual BAN::ErrorOr<size_t> write_impl(off_t, BAN::ConstByteSpan) override;
|
||||
//virtual BAN::ErrorOr<void> truncate_impl(size_t) override;
|
||||
//virtual BAN::ErrorOr<void> chmod_impl(mode_t) override;
|
||||
virtual BAN::ErrorOr<void> fsync_impl() override { return {}; }
|
||||
|
||||
virtual bool can_read_impl() const override { return true; }
|
||||
virtual bool can_write_impl() const override { return true; }
|
||||
|
|
|
@ -111,6 +111,7 @@ namespace Kernel
|
|||
BAN::ErrorOr<void> truncate(size_t);
|
||||
BAN::ErrorOr<void> chmod(mode_t);
|
||||
BAN::ErrorOr<void> chown(uid_t, gid_t);
|
||||
BAN::ErrorOr<void> fsync();
|
||||
|
||||
// Select/Non blocking API
|
||||
bool can_read() const;
|
||||
|
@ -145,6 +146,7 @@ namespace Kernel
|
|||
virtual BAN::ErrorOr<void> truncate_impl(size_t) { return BAN::Error::from_errno(ENOTSUP); }
|
||||
virtual BAN::ErrorOr<void> chmod_impl(mode_t) { return BAN::Error::from_errno(ENOTSUP); }
|
||||
virtual BAN::ErrorOr<void> chown_impl(uid_t, gid_t) { return BAN::Error::from_errno(ENOTSUP); }
|
||||
virtual BAN::ErrorOr<void> fsync_impl() = 0;
|
||||
|
||||
// Select/Non blocking API
|
||||
virtual bool can_read_impl() const = 0;
|
||||
|
|
|
@ -33,6 +33,7 @@ namespace Kernel
|
|||
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;
|
||||
virtual BAN::ErrorOr<void> fsync_impl() final override { return {}; }
|
||||
|
||||
virtual bool can_read_impl() const override { return m_buffer_size > 0; }
|
||||
virtual bool can_write_impl() const override { return true; }
|
||||
|
|
|
@ -51,6 +51,7 @@ namespace Kernel
|
|||
|
||||
BAN::ErrorOr<size_t> read_impl(off_t, BAN::ByteSpan buffer) override { return recvfrom_impl(buffer, nullptr, nullptr); }
|
||||
BAN::ErrorOr<size_t> write_impl(off_t, BAN::ConstByteSpan buffer) override { return sendto_impl(buffer, nullptr, 0); }
|
||||
BAN::ErrorOr<void> fsync_impl() final override { return {}; }
|
||||
|
||||
private:
|
||||
const Info m_info;
|
||||
|
|
|
@ -45,6 +45,8 @@ namespace Kernel
|
|||
protected:
|
||||
TmpInode(TmpFileSystem&, ino_t, const TmpInodeInfo&);
|
||||
|
||||
virtual BAN::ErrorOr<void> fsync_impl() override { return {}; }
|
||||
|
||||
void sync();
|
||||
void free_all_blocks();
|
||||
virtual BAN::ErrorOr<void> prepare_unlink() { return {}; };
|
||||
|
|
|
@ -143,6 +143,8 @@ namespace Kernel
|
|||
|
||||
BAN::ErrorOr<long> sys_truncate(int fd, off_t length);
|
||||
|
||||
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_realpath(const char* path, char* buffer);
|
||||
|
|
|
@ -20,10 +20,14 @@ namespace Kernel
|
|||
BAN::ErrorOr<void> write_to_cache(uint64_t sector, BAN::ConstByteSpan, bool dirty);
|
||||
|
||||
BAN::ErrorOr<void> sync();
|
||||
BAN::ErrorOr<void> sync(uint64_t sector, size_t sector_count);
|
||||
size_t release_clean_pages(size_t);
|
||||
size_t release_pages(size_t);
|
||||
void release_all_pages();
|
||||
|
||||
private:
|
||||
BAN::ErrorOr<void> sync_cache_index(size_t index);
|
||||
|
||||
private:
|
||||
struct PageCache
|
||||
{
|
||||
|
|
|
@ -15,13 +15,14 @@ namespace Kernel
|
|||
const BAN::GUID& partition_guid() const { return m_guid; }
|
||||
const BAN::RefPtr<BlockDevice> device() const { return m_device; }
|
||||
|
||||
virtual blksize_t blksize() const { return m_device->blksize(); }
|
||||
virtual blksize_t blksize() const override { return m_device->blksize(); }
|
||||
|
||||
BAN::ErrorOr<void> read_sectors(uint64_t first_block, size_t block_count, BAN::ByteSpan buffer) { return read_blocks(first_block, block_count, buffer); }
|
||||
BAN::ErrorOr<void> write_sectors(uint64_t first_block, size_t block_count, BAN::ConstByteSpan buffer) { return write_blocks(first_block, block_count, buffer); }
|
||||
|
||||
virtual BAN::ErrorOr<void> read_blocks(uint64_t first_block, size_t block_count, BAN::ByteSpan) override;
|
||||
virtual BAN::ErrorOr<void> write_blocks(uint64_t first_block, size_t block_count, BAN::ConstByteSpan) override;
|
||||
virtual BAN::ErrorOr<void> sync_blocks(uint64_t block, size_t block_count) override;
|
||||
|
||||
virtual BAN::StringView name() const override { return m_name; }
|
||||
|
||||
|
|
|
@ -21,11 +21,12 @@ namespace Kernel
|
|||
|
||||
virtual BAN::ErrorOr<void> read_blocks(uint64_t lba, size_t sector_count, BAN::ByteSpan buffer) override { return read_sectors(lba, sector_count, buffer); }
|
||||
virtual BAN::ErrorOr<void> write_blocks(uint64_t lba, size_t sector_count, BAN::ConstByteSpan buffer) override { return write_sectors(lba, sector_count, buffer); }
|
||||
virtual BAN::ErrorOr<void> sync_blocks(uint64_t block, size_t block_count) override;
|
||||
|
||||
BAN::ErrorOr<void> read_sectors(uint64_t lba, size_t sector_count, BAN::ByteSpan);
|
||||
BAN::ErrorOr<void> write_sectors(uint64_t lba, size_t sector_count, BAN::ConstByteSpan);
|
||||
|
||||
virtual blksize_t blksize() const { return sector_size(); }
|
||||
virtual blksize_t blksize() const override { return sector_size(); }
|
||||
virtual uint32_t sector_size() const = 0;
|
||||
virtual uint64_t total_size() const = 0;
|
||||
|
||||
|
|
|
@ -346,6 +346,17 @@ namespace Kernel
|
|||
return {};
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> Ext2FS::sync_block(uint32_t block)
|
||||
{
|
||||
LockGuard _(m_mutex);
|
||||
|
||||
const uint32_t sector_size = m_block_device->blksize();
|
||||
const uint32_t block_size = this->block_size();
|
||||
const uint32_t sectors_per_block = block_size / sector_size;
|
||||
|
||||
return m_block_device->sync_blocks(block * sectors_per_block, sectors_per_block);
|
||||
}
|
||||
|
||||
Ext2FS::BlockBufferWrapper Ext2FS::get_block_buffer()
|
||||
{
|
||||
LockGuard _(m_mutex);
|
||||
|
|
|
@ -259,6 +259,14 @@ namespace Kernel
|
|||
return {};
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> Ext2Inode::fsync_impl()
|
||||
{
|
||||
for (size_t i = 0; i < max_used_data_block_count(); i++)
|
||||
if (const auto fs_block = TRY(fs_block_of_data_block_index(i)); fs_block.has_value())
|
||||
TRY(m_fs.sync_block(fs_block.value()));
|
||||
return {};
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> Ext2Inode::cleanup_indirect_block(uint32_t block, uint32_t depth)
|
||||
{
|
||||
ASSERT(block);
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include <kernel/FS/Inode.h>
|
||||
#include <kernel/Lock/LockGuard.h>
|
||||
#include <kernel/Memory/FileBackedRegion.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
|
||||
|
@ -203,6 +204,15 @@ namespace Kernel
|
|||
return chown_impl(uid, gid);
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> Inode::fsync()
|
||||
{
|
||||
LockGuard _(m_mutex);
|
||||
if (auto shared = m_shared_region.lock())
|
||||
for (size_t i = 0; i < shared->pages.size(); i++)
|
||||
shared->sync(i);
|
||||
return fsync_impl();
|
||||
}
|
||||
|
||||
bool Inode::can_read() const
|
||||
{
|
||||
LockGuard _(m_mutex);
|
||||
|
|
|
@ -1448,6 +1448,14 @@ namespace Kernel
|
|||
return 0;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<long> Process::sys_fsync(int fd)
|
||||
{
|
||||
LockGuard _(m_process_lock);
|
||||
auto inode = TRY(m_open_file_descriptors.inode_of(fd));
|
||||
TRY(inode->fsync());
|
||||
return 0;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> Process::mount(BAN::StringView source, BAN::StringView target)
|
||||
{
|
||||
BAN::String absolute_source, absolute_target;
|
||||
|
|
|
@ -32,7 +32,7 @@ namespace Kernel
|
|||
|
||||
for (auto& cache : m_cache)
|
||||
{
|
||||
if (cache.first_sector < page_cache_start)
|
||||
if (cache.first_sector + sectors_per_page <= page_cache_start)
|
||||
continue;
|
||||
if (cache.first_sector > page_cache_start)
|
||||
break;
|
||||
|
@ -64,7 +64,7 @@ namespace Kernel
|
|||
{
|
||||
auto& cache = m_cache[index];
|
||||
|
||||
if (cache.first_sector < page_cache_start)
|
||||
if (cache.first_sector + sectors_per_page <= page_cache_start)
|
||||
continue;
|
||||
if (cache.first_sector > page_cache_start)
|
||||
break;
|
||||
|
@ -104,47 +104,73 @@ namespace Kernel
|
|||
return {};
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> DiskCache::sync()
|
||||
BAN::ErrorOr<void> DiskCache::sync_cache_index(size_t index)
|
||||
{
|
||||
if (g_disable_disk_write)
|
||||
auto& cache = m_cache[index];
|
||||
if (cache.dirty_mask == 0)
|
||||
return {};
|
||||
|
||||
for (auto& cache : m_cache)
|
||||
PageTable::with_fast_page(cache.paddr, [&] {
|
||||
memcpy(m_sync_cache.data(), PageTable::fast_page_as_ptr(), PAGE_SIZE);
|
||||
});
|
||||
|
||||
uint8_t sector_start = 0;
|
||||
uint8_t sector_count = 0;
|
||||
|
||||
while (sector_start + sector_count <= PAGE_SIZE / m_sector_size)
|
||||
{
|
||||
if (cache.dirty_mask == 0)
|
||||
continue;
|
||||
|
||||
PageTable::with_fast_page(cache.paddr, [&] {
|
||||
memcpy(m_sync_cache.data(), PageTable::fast_page_as_ptr(), PAGE_SIZE);
|
||||
});
|
||||
|
||||
uint8_t sector_start = 0;
|
||||
uint8_t sector_count = 0;
|
||||
|
||||
while (sector_start + sector_count <= PAGE_SIZE / m_sector_size)
|
||||
{
|
||||
if (cache.dirty_mask & (1 << (sector_start + sector_count)))
|
||||
sector_count++;
|
||||
else if (sector_count == 0)
|
||||
sector_start++;
|
||||
else
|
||||
{
|
||||
dprintln_if(DEBUG_DISK_SYNC, "syncing {}->{}", cache.first_sector + sector_start, cache.first_sector + sector_start + sector_count);
|
||||
auto data_slice = m_sync_cache.span().slice(sector_start * m_sector_size, sector_count * m_sector_size);
|
||||
TRY(m_device.write_sectors_impl(cache.first_sector + sector_start, sector_count, data_slice));
|
||||
sector_start += sector_count + 1;
|
||||
sector_count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (sector_count > 0)
|
||||
if (cache.dirty_mask & (1 << (sector_start + sector_count)))
|
||||
sector_count++;
|
||||
else if (sector_count == 0)
|
||||
sector_start++;
|
||||
else
|
||||
{
|
||||
dprintln_if(DEBUG_DISK_SYNC, "syncing {}->{}", cache.first_sector + sector_start, cache.first_sector + sector_start + sector_count);
|
||||
auto data_slice = m_sync_cache.span().slice(sector_start * m_sector_size, sector_count * m_sector_size);
|
||||
TRY(m_device.write_sectors_impl(cache.first_sector + sector_start, sector_count, data_slice));
|
||||
sector_start += sector_count + 1;
|
||||
sector_count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
cache.dirty_mask = 0;
|
||||
if (sector_count > 0)
|
||||
{
|
||||
dprintln_if(DEBUG_DISK_SYNC, "syncing {}->{}", cache.first_sector + sector_start, cache.first_sector + sector_start + sector_count);
|
||||
auto data_slice = m_sync_cache.span().slice(sector_start * m_sector_size, sector_count * m_sector_size);
|
||||
TRY(m_device.write_sectors_impl(cache.first_sector + sector_start, sector_count, data_slice));
|
||||
}
|
||||
|
||||
cache.dirty_mask = 0;
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> DiskCache::sync()
|
||||
{
|
||||
if (g_disable_disk_write)
|
||||
return {};
|
||||
for (size_t i = 0; i < m_cache.size(); i++)
|
||||
TRY(sync_cache_index(i));
|
||||
return {};
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> DiskCache::sync(uint64_t sector, size_t block_count)
|
||||
{
|
||||
if (g_disable_disk_write)
|
||||
return {};
|
||||
|
||||
uint64_t sectors_per_page = PAGE_SIZE / m_sector_size;
|
||||
uint64_t page_cache_offset = sector % sectors_per_page;
|
||||
uint64_t page_cache_start = sector - page_cache_offset;
|
||||
|
||||
for (size_t i = 0; i < m_cache.size(); i++)
|
||||
{
|
||||
auto& cache = m_cache[i];
|
||||
if (cache.first_sector + sectors_per_page <= page_cache_start)
|
||||
continue;
|
||||
if (cache.first_sector * sectors_per_page >= page_cache_start * sectors_per_page + block_count)
|
||||
break;
|
||||
TRY(sync_cache_index(i));
|
||||
}
|
||||
|
||||
return {};
|
||||
|
|
|
@ -48,6 +48,15 @@ namespace Kernel
|
|||
return {};
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> Partition::sync_blocks(uint64_t block, size_t block_count)
|
||||
{
|
||||
const uint32_t blocks_in_partition = m_last_block - m_first_block + 1;
|
||||
if (block + block_count > blocks_in_partition)
|
||||
return BAN::Error::from_error_code(ErrorCode::Storage_Boundaries);
|
||||
TRY(m_device->sync_blocks(m_first_block + block, block_count));
|
||||
return {};
|
||||
}
|
||||
|
||||
BAN::ErrorOr<size_t> Partition::read_impl(off_t offset, BAN::ByteSpan buffer)
|
||||
{
|
||||
ASSERT(offset >= 0);
|
||||
|
|
|
@ -286,6 +286,13 @@ namespace Kernel
|
|||
return {};
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> StorageDevice::sync_blocks(uint64_t block, size_t block_count)
|
||||
{
|
||||
if (!m_disk_cache.has_value())
|
||||
return {};
|
||||
return m_disk_cache->sync(block, block_count);
|
||||
}
|
||||
|
||||
BAN::ErrorOr<size_t> StorageDevice::read_impl(off_t offset, BAN::ByteSpan buffer)
|
||||
{
|
||||
if (offset % sector_size())
|
||||
|
|
|
@ -85,6 +85,7 @@ __BEGIN_DECLS
|
|||
O(SYS_SETITIMER, setitimer) \
|
||||
O(SYS_POSIX_OPENPT, posix_openpt) \
|
||||
O(SYS_PTSNAME, ptsname) \
|
||||
O(SYS_FSYNC, fsync) \
|
||||
|
||||
enum Syscall
|
||||
{
|
||||
|
|
|
@ -115,6 +115,11 @@ int ftruncate(int fildes, off_t length)
|
|||
return syscall(SYS_TRUNCATE, fildes, length);
|
||||
}
|
||||
|
||||
int fsync(int fildes)
|
||||
{
|
||||
return syscall(SYS_FSYNC, fildes);
|
||||
}
|
||||
|
||||
int dup(int fildes)
|
||||
{
|
||||
return syscall(SYS_DUP, fildes);
|
||||
|
|
Loading…
Reference in New Issue