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