From 76c090b694267c2536cad4a7094bd2bc79f934bd Mon Sep 17 00:00:00 2001 From: Norman Feske Date: Fri, 4 Feb 2022 13:41:49 +0100 Subject: [PATCH] Remove block_cache server Issue #4405 --- repos/gems/run/depot_autopilot.run | 1 - repos/libports/src/lib/vfs/fatfs/README | 7 +- repos/os/recipes/pkg/test-block_cache/README | 1 - .../os/recipes/pkg/test-block_cache/archives | 3 - repos/os/recipes/pkg/test-block_cache/hash | 1 - repos/os/recipes/pkg/test-block_cache/runtime | 54 -- repos/os/recipes/src/block_cache/content.mk | 2 - repos/os/recipes/src/block_cache/hash | 1 - repos/os/recipes/src/block_cache/used_apis | 3 - repos/os/src/server/block_cache/chunk.h | 594 ------------------ repos/os/src/server/block_cache/driver.h | 421 ------------- repos/os/src/server/block_cache/lru.cc | 62 -- repos/os/src/server/block_cache/lru.h | 25 - repos/os/src/server/block_cache/main.cc | 94 --- repos/os/src/server/block_cache/target.mk | 5 - 15 files changed, 3 insertions(+), 1271 deletions(-) delete mode 100644 repos/os/recipes/pkg/test-block_cache/README delete mode 100644 repos/os/recipes/pkg/test-block_cache/archives delete mode 100644 repos/os/recipes/pkg/test-block_cache/hash delete mode 100644 repos/os/recipes/pkg/test-block_cache/runtime delete mode 100644 repos/os/recipes/src/block_cache/content.mk delete mode 100644 repos/os/recipes/src/block_cache/hash delete mode 100644 repos/os/recipes/src/block_cache/used_apis delete mode 100644 repos/os/src/server/block_cache/chunk.h delete mode 100644 repos/os/src/server/block_cache/driver.h delete mode 100644 repos/os/src/server/block_cache/lru.cc delete mode 100644 repos/os/src/server/block_cache/lru.h delete mode 100644 repos/os/src/server/block_cache/main.cc delete mode 100644 repos/os/src/server/block_cache/target.mk diff --git a/repos/gems/run/depot_autopilot.run b/repos/gems/run/depot_autopilot.run index df6ad9340a..4e876df5c7 100644 --- a/repos/gems/run/depot_autopilot.run +++ b/repos/gems/run/depot_autopilot.run @@ -650,7 +650,6 @@ set default_test_pkgs { test-spark_exception test-spark_secondary_stack test-block - test-block_cache test-clipboard test-depot_query_index test-ds_ownership diff --git a/repos/libports/src/lib/vfs/fatfs/README b/repos/libports/src/lib/vfs/fatfs/README index bb56f1b9f0..d39a44f2ee 100644 --- a/repos/libports/src/lib/vfs/fatfs/README +++ b/repos/libports/src/lib/vfs/fatfs/README @@ -6,8 +6,7 @@ Usage The plugin takes no configuration options. Caching -~~~~~~~~ +~~~~~~~ -This plugin may cache some file data but schedules a full write cache flush a few -seconds after any write operation. If a read caching is desired, please use the -'block_cache' component to cache at the block device. +This plugin may cache some file data but schedules a full write cache flush a +few seconds after any write operation. diff --git a/repos/os/recipes/pkg/test-block_cache/README b/repos/os/recipes/pkg/test-block_cache/README deleted file mode 100644 index c96e30355b..0000000000 --- a/repos/os/recipes/pkg/test-block_cache/README +++ /dev/null @@ -1 +0,0 @@ -Test of Block session interface provided by server/block_cache diff --git a/repos/os/recipes/pkg/test-block_cache/archives b/repos/os/recipes/pkg/test-block_cache/archives deleted file mode 100644 index 072cefacf3..0000000000 --- a/repos/os/recipes/pkg/test-block_cache/archives +++ /dev/null @@ -1,3 +0,0 @@ -_/src/init -_/src/test-block -_/src/block_cache diff --git a/repos/os/recipes/pkg/test-block_cache/hash b/repos/os/recipes/pkg/test-block_cache/hash deleted file mode 100644 index 74f0362d61..0000000000 --- a/repos/os/recipes/pkg/test-block_cache/hash +++ /dev/null @@ -1 +0,0 @@ -2022-01-18 402df20aabf69c4ef0a36901ff6fb26f6a1644c9 diff --git a/repos/os/recipes/pkg/test-block_cache/runtime b/repos/os/recipes/pkg/test-block_cache/runtime deleted file mode 100644 index b156bed312..0000000000 --- a/repos/os/recipes/pkg/test-block_cache/runtime +++ /dev/null @@ -1,54 +0,0 @@ - - - - - - - --- all tests finished --- - test-block-client] Error: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/repos/os/recipes/src/block_cache/content.mk b/repos/os/recipes/src/block_cache/content.mk deleted file mode 100644 index 9c21183d62..0000000000 --- a/repos/os/recipes/src/block_cache/content.mk +++ /dev/null @@ -1,2 +0,0 @@ -SRC_DIR = src/server/block_cache -include $(GENODE_DIR)/repos/base/recipes/src/content.inc diff --git a/repos/os/recipes/src/block_cache/hash b/repos/os/recipes/src/block_cache/hash deleted file mode 100644 index f54316727c..0000000000 --- a/repos/os/recipes/src/block_cache/hash +++ /dev/null @@ -1 +0,0 @@ -2022-01-18 fadb7bcdf02aa959281f51a432f36525157492cb diff --git a/repos/os/recipes/src/block_cache/used_apis b/repos/os/recipes/src/block_cache/used_apis deleted file mode 100644 index 1dc350cf5c..0000000000 --- a/repos/os/recipes/src/block_cache/used_apis +++ /dev/null @@ -1,3 +0,0 @@ -base -os -block_session diff --git a/repos/os/src/server/block_cache/chunk.h b/repos/os/src/server/block_cache/chunk.h deleted file mode 100644 index 658e973bc7..0000000000 --- a/repos/os/src/server/block_cache/chunk.h +++ /dev/null @@ -1,594 +0,0 @@ -/* - * \brief Data structure for storing sparse blocks - * \author Norman Feske - * \author Stefan Kalkowski - * \date 2014-01-06 - * - * Note: originally taken from vfs/ram, and adapted to cache needs - */ - -/* - * Copyright (C) 2014-2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#ifndef _CHUNK_H_ -#define _CHUNK_H_ - -/* Genode includes */ -#include -#include -#include -#include -#include - -namespace Cache { - - typedef Genode::uint64_t offset_t; - typedef Genode::uint64_t size_t; - - /** - * Common base class of both 'Chunk' and 'Chunk_index' - */ - class Chunk_base : Genode::Noncopyable - { - private: - - /* - * Noncopyable - */ - Chunk_base(Chunk_base const &); - Chunk_base &operator = (Chunk_base const &); - - public: - - struct Range_exception : Genode::Exception - { - offset_t off; - size_t size; - - Range_exception(offset_t o, size_t s) : off(o), size(s) {} - }; - - typedef Range_exception Index_out_of_range; - typedef Range_exception Range_incomplete; - - protected: - - offset_t const _base_offset; - size_t _num_entries; /* corresponds to last used entry */ - Chunk_base *_parent; - bool const _zero; /* marks zero chunk */ - - /** - * Test if specified range lies within the chunk - */ - void assert_valid_range(offset_t start, size_t len, - size_t chunk_size) const - { - if (start < _base_offset) - throw Index_out_of_range(start, len); - - if (start + len > _base_offset + chunk_size) - throw Index_out_of_range(start, len); - } - - Chunk_base(offset_t base_offset, Chunk_base *p) - : _base_offset(base_offset), _num_entries(0), _parent(p), - _zero(false) { } - - /** - * Construct zero chunk - */ - Chunk_base() - : _base_offset(0), _num_entries(0), _parent(0), _zero(true) { } - - public: - - virtual ~Chunk_base() { } - - /** - * Return absolute base offset of chunk in bytes - */ - offset_t base_offset() const { return _base_offset; } - - /** - * Return true if chunk has no allocated sub chunks - */ - bool empty() const { return _num_entries == 0; } - - /** - * Return true if this is an unused 'zero' chunk - */ - bool zero() const { return _zero; } - - virtual void free(size_t, offset_t) = 0; - }; - - - /** - * Chunk of bytes used as leaf in hierarchy of chunk indices - */ - template - class Chunk : public Chunk_base, - public POLICY::Element - { - private: - - char _data[CHUNK_SIZE]; - unsigned _writes; - - public: - - typedef Range_exception Dirty_chunk; - - static constexpr size_t SIZE = CHUNK_SIZE; - - /** - * Construct byte chunk - * - * \param base_offset absolute offset of chunk in bytes - * - * The first argument is unused. Its mere purpose is to make the - * signature of the constructor compatible to the constructor - * of 'Chunk_index'. - */ - Chunk(Genode::Allocator &, offset_t base_offset, Chunk_base *p) - : Chunk_base(base_offset, p), _writes(0) { } - - /** - * Construct zero chunk - */ - Chunk() : _writes(0) { } - - /** - * Return number of used entries - * - * The returned value corresponds to the index of the last used - * entry + 1. It does not correlate to the number of actually - * allocated entries (there may be ranges of zero blocks). - */ - size_t used_size() const { return _num_entries; } - - void write(char const *src, size_t len, offset_t seek_offset) - { - assert_valid_range(seek_offset, len, SIZE); - - POLICY::write(this); - - /* offset relative to this chunk */ - offset_t const local_offset = seek_offset - base_offset(); - - Genode::memcpy(&_data[local_offset], src, len); - - _num_entries = Genode::max(_num_entries, local_offset + len); - - _writes++; - } - - void read(char *dst, size_t len, offset_t seek_offset) const - { - assert_valid_range(seek_offset, len, SIZE); - - POLICY::read(this); - - Genode::memcpy(dst, &_data[seek_offset - base_offset()], len); - } - - void stat(size_t len, offset_t seek_offset) const - { - assert_valid_range(seek_offset, len, SIZE); - - if (_writes == 0) - throw Range_incomplete(base_offset(), SIZE); - } - - void sync(size_t len, offset_t seek_offset) - { - if (_writes > 1) { - POLICY::sync(this, (char*)_data); - _writes = 1; - } - } - - void alloc(size_t len, offset_t seek_offset) { } - - void truncate(size_t size) - { - assert_valid_range(size, 0, SIZE); - - /* - * Offset of the first free position (relative to the beginning - * this chunk). - */ - offset_t const local_offset = size - base_offset(); - - if (local_offset >= _num_entries) - return; - - Genode::memset(&_data[local_offset], 0, _num_entries - local_offset); - - _num_entries = local_offset; - } - - void free(size_t, offset_t) - { - if (_writes > 1) throw Dirty_chunk(_base_offset, SIZE); - - _num_entries = 0; - if (_parent) _parent->free(SIZE, _base_offset); - } - }; - - - template - class Chunk_index : public Chunk_base - { - public: - - typedef ENTRY_TYPE Entry; - - static constexpr size_t ENTRY_SIZE = ENTRY_TYPE::SIZE; - static constexpr size_t SIZE = ENTRY_SIZE*NUM_ENTRIES; - - private: - - /* - * Noncopyable - */ - Chunk_index(Chunk_index const &); - Chunk_index &operator = (Chunk_index const &); - - Genode::Allocator &_alloc; - - Entry * _entries[NUM_ENTRIES]; - - /** - * Return instance of a zero sub chunk - */ - static Entry &_zero_chunk() - { - static Entry zero_chunk; - return zero_chunk; - } - - /** - * Return sub chunk at given index - * - * If there is no sub chunk at the specified index, this function - * transparently allocates one. Hence, the returned sub chunk - * is ready to be written to. - */ - Entry &_alloc_entry(unsigned index) - { - if (index >= NUM_ENTRIES) - throw Index_out_of_range(base_offset() + index*ENTRY_SIZE, - ENTRY_SIZE); - - if (_entries[index]) - return *_entries[index]; - - offset_t entry_offset = base_offset() + index*ENTRY_SIZE; - - for (;;) { - try { - _entries[index] = new (&_alloc) - Entry(_alloc, entry_offset, this); - break; - } catch(Genode::Allocator::Out_of_memory) { - POLICY::flush(sizeof(Entry)); - } - } - - _num_entries = Genode::max(_num_entries, index + 1); - - return *_entries[index]; - } - - /** - * Return sub chunk at given index - */ - Entry &_entry(unsigned index) const - { - if (index >= NUM_ENTRIES) - throw Index_out_of_range(base_offset() + index*ENTRY_SIZE, - ENTRY_SIZE); - - if (_entries[index]) - return *_entries[index]; - - throw Range_incomplete(base_offset() + index*ENTRY_SIZE, - ENTRY_SIZE); - } - - /** - * Return sub chunk at given index (for syncing only) - * - * This function transparently provides a zero sub chunk for any - * index that is not populated by a real chunk. - */ - Entry &_entry_for_syncing(unsigned index) const - { - if (index >= NUM_ENTRIES) - throw Index_out_of_range(base_offset() + index*ENTRY_SIZE, - ENTRY_SIZE); - - if (_entries[index]) - return *_entries[index]; - - return _zero_chunk(); - } - - - /** - * Return index of entry located at specified byte offset - * - * The caller of this function must make sure that the offset - * parameter is within the bounds of the chunk. - */ - unsigned _index_by_offset(offset_t offset) const - { - return (offset - base_offset()) / ENTRY_SIZE; - } - - /** - * Apply operation 'func' to a range of entries - */ - template - static void _range_op(THIS &obj, DATA *data, size_t len, - offset_t seek_offset, FUNC const &func) - { - /* - * Depending on whether this function is called for reading - * (const function) or writing (non-const function), the - * operand type is const or non-const Entry. The correct type - * is embedded as a trait in the 'FUNC' functor type. - */ - typedef typename FUNC::Entry Const_qualified_entry; - - obj.assert_valid_range(seek_offset, len, SIZE); - - while (len > 0) { - - unsigned const index = obj._index_by_offset(seek_offset); - - Const_qualified_entry &entry = FUNC::lookup(obj, index); - - /* - * Calculate byte offset relative to the chunk - * - * We cannot use 'entry.base_offset()' for this calculation - * because in the const case, the lookup might return a - * zero chunk, which has no defined base offset. Therefore, - * we calculate the base offset via index*ENTRY_SIZE. - */ - offset_t const local_seek_offset = - seek_offset - obj.base_offset() - index*ENTRY_SIZE; - - /* available capacity at 'entry' starting at seek offset */ - offset_t const capacity = ENTRY_SIZE - local_seek_offset; - size_t const curr_len = Genode::min(len, capacity); - - /* apply functor (read or write) to entry */ - func(entry, data, curr_len, seek_offset); - - /* advance to next entry */ - len -= curr_len; - data += curr_len; - seek_offset += curr_len; - } - } - - struct Alloc_func - { - typedef ENTRY_TYPE Entry; - - static Entry &lookup(Chunk_index &chunk, unsigned i) { - return chunk._alloc_entry(i); } - - void operator () (Entry &entry, char const *src, size_t len, - offset_t seek_offset) const - { - entry.alloc(len, seek_offset); - } - }; - - struct Write_func - { - typedef ENTRY_TYPE Entry; - - static Entry &lookup(Chunk_index &chunk, unsigned i) { - return chunk._entry(i); } - - void operator () (Entry &entry, char const *src, size_t len, - offset_t seek_offset) const - { - entry.write(src, len, seek_offset); - } - }; - - struct Read_func - { - typedef ENTRY_TYPE const Entry; - - static Entry &lookup(Chunk_index const &chunk, unsigned i) { - return chunk._entry(i); } - - void operator () (Entry &entry, char *dst, size_t len, - offset_t seek_offset) const { - entry.read(dst, len, seek_offset); } - }; - - struct Stat_func - { - typedef ENTRY_TYPE const Entry; - - static Entry &lookup(Chunk_index const &chunk, unsigned i) { - return chunk._entry(i); } - - void operator () (Entry &entry, char*, size_t len, - offset_t seek_offset) const { - entry.stat(len, seek_offset); } - }; - - struct Sync_func - { - typedef ENTRY_TYPE Entry; - - static Entry &lookup(Chunk_index const &chunk, unsigned i) { - return chunk._entry_for_syncing(i); } - - void operator () (Entry &entry, char*, size_t len, - offset_t seek_offset) const - { - entry.sync(len, seek_offset); - } - }; - - void _init_entries() - { - for (unsigned i = 0; i < NUM_ENTRIES; i++) - _entries[i] = 0; - } - - void _destroy_entry(unsigned i) - { - if (_entries[i] && (i < _num_entries)) { - Genode::destroy(&_alloc, _entries[i]); - _entries[i] = 0; - } - } - - public: - - /** - * Constructor - * - * \param alloc allocator to use for allocating sub-chunk - * indices and chunks - * \param base_offset absolute offset of the chunk in bytes - */ - Chunk_index(Genode::Allocator &alloc, offset_t base_offset, - Chunk_base *p = 0) - : Chunk_base(base_offset, p), _alloc(alloc) { _init_entries(); } - - /** - * Construct zero chunk - */ - Chunk_index() : _alloc(*(Genode::Allocator *)0) { } - - /** - * Destructor - */ - ~Chunk_index() - { - for (unsigned i = 0; i < NUM_ENTRIES; i++) - _destroy_entry(i); - } - - /** - * Return size of chunk in bytes - * - * The returned value corresponds to the position after the highest - * offset that was written to. - */ - size_t used_size() const - { - if (_num_entries == 0) - return 0; - - /* size of entries that lie completely within the used range */ - size_t const size_whole_entries = ENTRY_SIZE*(_num_entries - 1); - - Entry *last_entry = _entries[_num_entries - 1]; - if (!last_entry) - return size_whole_entries; - - return size_whole_entries + last_entry->used_size(); - } - - /** - * Write data to chunk - */ - void write(char const *src, size_t len, offset_t seek_offset) { - _range_op(*this, src, len, seek_offset, Write_func()); } - - /** - * Allocate needed chunks - */ - void alloc(size_t len, offset_t seek_offset) { - _range_op(*this, (char*)0, len, seek_offset, Alloc_func()); } - - /** - * Read data from chunk - */ - void read(char *dst, size_t len, offset_t seek_offset) const { - _range_op(*this, dst, len, seek_offset, Read_func()); } - - /** - * Check for chunk availability - */ - void stat(size_t len, offset_t seek_offset) const { - _range_op(*this, (char*)0, len, seek_offset, Stat_func()); } - - /** - * Synchronize chunk when dirty - */ - void sync(size_t len, offset_t seek_offset) const { - if (zero()) return; - _range_op(*this, (char*)0, len, seek_offset, Sync_func()); } - - /** - * Free chunks - */ - void free(size_t len, offset_t seek_offset) - { - unsigned const index = _index_by_offset(seek_offset); - Genode::destroy(&_alloc, _entries[index]); - _entries[index] = 0; - for (unsigned i = 0; i < NUM_ENTRIES; i++) - if (_entries[i]) - return; - - if (_parent) _parent->free(SIZE, _base_offset); - } - - /** - * Truncate chunk to specified size in bytes - * - * This function can be used to shrink a chunk only. Specifying a - * 'size' larger than 'used_size' has no effect. The value returned - * by 'used_size' refers always to the position of the last byte - * written to the chunk. - */ - void truncate(size_t size) - { - unsigned const trunc_index = _index_by_offset(size); - - if (trunc_index >= _num_entries) - return; - - for (unsigned i = trunc_index + 1; i < _num_entries; i++) - _destroy_entry(i); - - /* traverse into sub chunks */ - if (_entries[trunc_index]) - _entries[trunc_index]->truncate(size); - - _num_entries = trunc_index + 1; - - /* - * If the truncated at a chunk boundary, we can release the - * empty trailing chunk at 'trunc_index'. - */ - if (_entries[trunc_index] && _entries[trunc_index]->empty()) { - _destroy_entry(trunc_index); - _num_entries--; - } - } - }; -}; - -#endif /* _CHUNK_H_ */ diff --git a/repos/os/src/server/block_cache/driver.h b/repos/os/src/server/block_cache/driver.h deleted file mode 100644 index cbc93b8de3..0000000000 --- a/repos/os/src/server/block_cache/driver.h +++ /dev/null @@ -1,421 +0,0 @@ -/* - * \brief Cache driver - * \author Stefan Kalkowski - * \date 2013-12-05 - */ - -/* - * Copyright (C) 2013-2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#include -#include -#include -#include - -#include "chunk.h" - -/** - * Cache driver used by the generic block driver framework - * - * \param POLICY the cache replacement policy (e.g. LRU) - */ -template -class Driver : public Block::Driver -{ - private: - - /** - * This class encapsulates requests to the backend device in progress, - * and the packets from the client side that triggered the request. - */ - struct Request : public Genode::List::Element - { - Block::Packet_descriptor srv; - Block::Packet_descriptor cli; - char * const buffer; - - Request(Block::Packet_descriptor &s, - Block::Packet_descriptor &c, - char * const b) - : srv(s), cli(c), buffer(b) {} - - /* - * \return true when the given response packet matches - * the request send to the backend device - */ - bool match(const Block::Packet_descriptor& reply) const - { - return reply.operation() == srv.operation() && - reply.block_number() == srv.block_number() && - reply.block_count() == srv.block_count(); - } - - /* - * \param write whether it's a write or read request - * \param nr block number requested - * \param cnt number of blocks requested - * \return true when the given parameters match - * the request send to the backend device - */ - bool match(const bool write, - const Block::sector_t nr, - const Genode::size_t cnt) const - { - Block::Packet_descriptor::Opcode op = write - ? Block::Packet_descriptor::WRITE - : Block::Packet_descriptor::READ; - return op == srv.operation() && - nr >= srv.block_number() && - nr+cnt <= srv.block_number()+srv.block_count(); - } - }; - - - /** - * Write failed exception at a specific device offset, - * can be triggered whenever the backend device is not ready - * to proceed - */ - struct Write_failed : Genode::Exception - { - Cache::offset_t off; - - Write_failed(Cache::offset_t o) : off(o) {} - }; - - - /* - * The given policy class is extended by a synchronization routine, - * used by the cache chunk structure - */ - struct Policy : POLICY { - static void sync(const typename POLICY::Element *e, char *src); }; - - public: - - enum { - SLAB_SZ = Block::Session::TX_QUEUE_SIZE*sizeof(Request), - CACHE_BLK_SIZE = 4096 - }; - - /** - * We use five levels of page-table like chunk structure, - * thereby we've a maximum device size of 256^4*4096 (LBA48) - */ - typedef Cache::Chunk Chunk_level_4; - typedef Cache::Chunk_index<256, Chunk_level_4, Policy> Chunk_level_3; - typedef Cache::Chunk_index<256, Chunk_level_3, Policy> Chunk_level_2; - typedef Cache::Chunk_index<256, Chunk_level_2, Policy> Chunk_level_1; - typedef Cache::Chunk_index<256, Chunk_level_1, Policy> Chunk_level_0; - - private: - - Genode::Env &_env; - Genode::Tslab _r_slab; /* slab for requests */ - Genode::List _r_list; /* list of requests */ - Genode::Packet_allocator _alloc; /* packet allocator */ - Block::Connection<> _blk; /* backend device */ - Block::Session::Info const _info; /* block-device info */ - Chunk_level_0 _cache; /* chunk hierarchy */ - Genode::Io_signal_handler _source_ack; - Genode::Io_signal_handler _source_submit; - Genode::Io_signal_handler _yield; - - Driver(Driver const&); /* singleton pattern */ - Driver& operator=(Driver const&); /* singleton pattern */ - - /* - * Return modulus of cache's versus backend device's block size - */ - inline int _cache_blk_mod() { return CACHE_BLK_SIZE / _info.block_size; } - - /* - * Round off given block number to cache block size granularity - */ - inline Block::sector_t _cache_blk_round_off(Block::sector_t nr) { - return nr - (nr % _cache_blk_mod()); } - - /* - * Round up given block number to cache block size granularity - */ - inline Block::sector_t _cache_blk_round_up(Block::sector_t nr) { - return (nr % _cache_blk_mod()) - ? nr + _cache_blk_mod() - (nr % _cache_blk_mod()) - : nr; } - - /* - * Handle response to a single request - * - * \param srv packet received from the backend device - * \param r outstanding request - */ - inline void _handle_reply(Block::Packet_descriptor &srv, Request *r) - { - try { - if (r->cli.operation() == Block::Packet_descriptor::READ) - read(r->cli.block_number(), r->cli.block_count(), - r->buffer, r->cli); - else - write(r->cli.block_number(), r->cli.block_count(), - r->buffer, r->cli); - } catch(Block::Driver::Request_congestion) { - Genode::warning("cli (", r->cli.block_number(), " ", - r->cli.block_count(), ") " - "srv (", r->srv.block_number(), " ", - r->srv.block_count(), ")"); - } - } - - /* - * Handle acknowledgements from the backend device - */ - void _ack_avail() - { - while (_blk.tx()->ack_avail()) { - Block::Packet_descriptor p = _blk.tx()->get_acked_packet(); - - /* when reading, write result into cache */ - if (p.operation() == Block::Packet_descriptor::READ) - _cache.write(_blk.tx()->packet_content(p), - p.block_count() * _info.block_size, - p.block_number() * _info.block_size); - - /* loop through the list of requests, and ack all related */ - for (Request *r = _r_list.first(), *r_to_handle = r; r; - r_to_handle = r) { - r = r->next(); - if (r_to_handle->match(p)) { - _handle_reply(p, r_to_handle); - _r_list.remove(r_to_handle); - Genode::destroy(&_r_slab, r_to_handle); - } - } - - _blk.tx()->release_packet(p); - } - } - - /* - * Handle that the backend device is ready to receive again - */ - void _ready_to_submit() { } - - /* - * Setup a request to the backend device - * - * \param block_number block number offset - * \param block_count number of blocks - * \param packet original packet request received from the client - */ - void _request(Block::sector_t block_number, - Genode::size_t block_count, - char * const buffer, - Block::Packet_descriptor &packet) - { - Block::Packet_descriptor p_to_dev; - - try { - /* we've to look whether the request is already pending */ - for (Request *r = _r_list.first(); r; r = r->next()) { - if (r->match(false, block_number, block_count)) { - _r_list.insert(new (&_r_slab) Request(r->srv, packet, - buffer)); - return; - } - } - - /* it doesn't pay, we've to send a request to the device */ - if (!_blk.tx()->ready_to_submit()) { - Genode::warning("not ready_to_submit"); - throw Request_congestion(); - } - - /* read ahead CACHE_BLK_SIZE */ - Block::sector_t nr = _cache_blk_round_off(block_number); - Genode::size_t cnt = _cache_blk_round_up(block_count + - (block_number - nr)); - - /* ensure all memory is available before sending the request */ - _cache.alloc(cnt * _info.block_size, nr * _info.block_size); - - /* construct and send the packet */ - p_to_dev = - Block::Packet_descriptor(_blk.alloc_packet(_info.block_size*cnt), - Block::Packet_descriptor::READ, - nr, cnt); - _r_list.insert(new (&_r_slab) Request(p_to_dev, packet, buffer)); - _blk.tx()->submit_packet(p_to_dev); - } catch(Block::Session::Tx::Source::Packet_alloc_failed) { - throw Request_congestion(); - } catch(Genode::Allocator::Out_of_memory) { - /* clean up */ - _blk.tx()->release_packet(p_to_dev); - throw Request_congestion(); - } - } - - /* - * Synchronize dirty chunks with backend device - */ - void _sync() - { - Cache::offset_t off = 0; - Cache::size_t len = _info.block_size * _info.block_count; - - while (len > 0) { - try { - _cache.sync(len, off); - len = 0; - } catch(Write_failed &e) { - /** - * Write to backend failed when backend device isn't ready - * to proceed, so handle signals, until it's ready again - */ - off = e.off; - len = _info.block_size * _info.block_count - off; - _env.ep().wait_and_dispatch_one_io_signal(); - } - } - } - - /* - * Check for chunk availability - * - * \param nr block number offset - * \param cnt number of blocks - * \param p client side packet, which triggered this operation - */ - bool _stat(Block::sector_t nr, Genode::size_t cnt, - char * const buffer, Block::Packet_descriptor &p) - { - Cache::offset_t off = nr * _info.block_size; - Cache::size_t size = cnt * _info.block_size; - Cache::offset_t end = off + size; - - try { - _cache.stat(size, off); - return true; - } catch(Cache::Chunk_base::Range_incomplete &e) { - off = Genode::max(off, e.off); - size = Genode::min(end - off, e.size); - _request(off / _info.block_size, size / _info.block_size, buffer, p); - } - return false; - } - - /* - * Signal handler for yield requests of the parent - */ - void _parent_yield() - { - using namespace Genode; - - Parent::Resource_args const args = _env.parent().yield_request(); - size_t const requested_ram_quota = - Arg_string::find_arg(args.string(), "ram_quota").ulong_value(0); - - /* flush the requested amount of RAM from cache */ - POLICY::flush(requested_ram_quota); - _env.parent().yield_response(); - } - - public: - - /* - * Constructor - * - * \param ep server entrypoint - */ - Driver(Genode::Env &env, Genode::Heap &heap) - : Block::Driver(env.ram()), - _env(env), - _r_slab(&heap), - _alloc(&heap, CACHE_BLK_SIZE), - _blk(_env, &_alloc, Block::Session::TX_QUEUE_SIZE*CACHE_BLK_SIZE), - _info(_blk.info()), - _cache(heap, 0), - _source_ack(env.ep(), *this, &Driver::_ack_avail), - _source_submit(env.ep(), *this, &Driver::_ready_to_submit), - _yield(env.ep(), *this, &Driver::_parent_yield) - { - using namespace Genode; - - _blk.tx_channel()->sigh_ack_avail(_source_ack); - _blk.tx_channel()->sigh_ready_to_submit(_source_submit); - env.parent().yield_sigh(_yield); - - if (CACHE_BLK_SIZE % _info.block_size) { - error("only devices that block size is divider of ", - Hex(CACHE_BLK_SIZE, Hex::OMIT_PREFIX) ," supported"); - throw Io_error(); - } - - /* truncate chunk structure to real size of the device */ - _cache.truncate(_info.block_size * _info.block_count); - } - - ~Driver() - { - /* when session gets closed, synchronize and flush the cache */ - _sync(); - POLICY::flush(); - } - - Block::Session_client* blk() { return &_blk; } - Genode::size_t blk_sz() { return _info.block_size; } - - - /**************************** - ** Block-driver interface ** - ****************************/ - - Block::Session::Info info() const override { return _info; } - - void read(Block::sector_t block_number, - Genode::size_t block_count, - char* buffer, - Block::Packet_descriptor &packet) - { - if (!_stat(block_number, block_count, buffer, packet)) - return; - - _cache.read(buffer, - block_count *_info.block_size, - block_number*_info.block_size); - - ack_packet(packet); - } - - void write(Block::sector_t block_number, - Genode::size_t block_count, - const char * buffer, - Block::Packet_descriptor &packet) - { - if (!_info.writeable) - throw Io_error(); - - _cache.alloc(block_count * _info.block_size, - block_number * _info.block_size); - - if ((block_number % _cache_blk_mod()) && - !_stat(block_number, 1, const_cast(buffer), packet)) - return; - - if (((block_number+block_count) % _cache_blk_mod()) - && !_stat(block_number+block_count-1, 1, - const_cast(buffer), packet)) - return; - - _cache.write(buffer, - block_count * _info.block_size, - block_number * _info.block_size); - - ack_packet(packet); - } - - void sync() { _sync(); } -}; diff --git a/repos/os/src/server/block_cache/lru.cc b/repos/os/src/server/block_cache/lru.cc deleted file mode 100644 index 986a529d7c..0000000000 --- a/repos/os/src/server/block_cache/lru.cc +++ /dev/null @@ -1,62 +0,0 @@ -/* - * \brief Least-recently-used cache replacement strategy - * \author Stefan Kalkowski - * \date 2013-12-05 - */ - -/* - * Copyright (C) 2013-2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#include "lru.h" -#include "driver.h" - -typedef Driver::Chunk_level_4 Chunk; - -static const Lru_policy::Element *lru = 0; -static Genode::List lru_list; - - -static void lru_access(const Lru_policy::Element *e) -{ - if (e == lru) return; - - if (e->next()) lru_list.remove(e); - - lru_list.insert(e, lru); - lru = e; -} - - -void Lru_policy::read(const Lru_policy::Element *e) { - lru_access(e); } - - -void Lru_policy::write(const Lru_policy::Element *e) { - lru_access(e); } - - -void Lru_policy::flush(Cache::size_t size) -{ - Cache::size_t s = 0; - for (Lru_policy::Element *e = lru_list.first(); - e && ((size == 0) || (s < size)); - e = lru_list.first(), s += sizeof(Chunk)) { - Chunk *cb = static_cast(e); - e = e->next(); - try { - cb->free(Driver::CACHE_BLK_SIZE, - cb->base_offset()); - lru_list.remove(cb); - } catch(Chunk::Dirty_chunk &e) { - cb->sync(e.size, e.off); - } - } - - if (!lru_list.first()) lru = 0; - - if (s < size) throw Block::Driver::Request_congestion(); -} diff --git a/repos/os/src/server/block_cache/lru.h b/repos/os/src/server/block_cache/lru.h deleted file mode 100644 index 5dbb340d07..0000000000 --- a/repos/os/src/server/block_cache/lru.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * \brief Least-recently-used cache replacement strategy - * \author Stefan Kalkowski - * \date 2013-12-05 - */ - -/* - * Copyright (C) 2013-2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#include - -#include "chunk.h" - -struct Lru_policy -{ - class Element : public Genode::List::Element {}; - - static void read(const Element *e); - static void write(const Element *e); - static void flush(Cache::size_t size = 0); -}; diff --git a/repos/os/src/server/block_cache/main.cc b/repos/os/src/server/block_cache/main.cc deleted file mode 100644 index b2af7b6345..0000000000 --- a/repos/os/src/server/block_cache/main.cc +++ /dev/null @@ -1,94 +0,0 @@ -/* - * \brief Cache a block device - * \author Stefan Kalkowski - * \date 2013-12-05 - */ - -/* - * Copyright (C) 2013-2017 Genode Labs GmbH - * - * This file is part of the Genode OS framework, which is distributed - * under the terms of the GNU Affero General Public License version 3. - */ - -#include - -#include "lru.h" -#include "driver.h" - -using Policy = Lru_policy; -static Driver * driver = nullptr; - - -/** - * Synchronize a chunk with the backend device - */ -template -void Driver::Policy::sync(const typename POLICY::Element *e, char *dst) -{ - Cache::offset_t off = - static_cast::Chunk_level_4*>(e)->base_offset(); - - if (!driver) throw Write_failed(off); - - if (!driver->blk()->tx()->ready_to_submit()) - throw Write_failed(off); - try { - Block::Packet_descriptor - p(driver->blk()->alloc_packet(Driver::CACHE_BLK_SIZE), - Block::Packet_descriptor::WRITE, off / driver->blk_sz(), - Driver::CACHE_BLK_SIZE / driver->blk_sz()); - driver->blk()->tx()->submit_packet(p); - } catch(Block::Session::Tx::Source::Packet_alloc_failed) { - throw Write_failed(off); - } -} - -/* explicit instantiation for external reference */ -template void Driver::Policy::sync(const typename Policy::Element *, char *); - - -struct Main -{ - template - struct Factory : Block::Driver_factory - { - Genode::Env &env; - Genode::Heap &heap; - - Factory(Genode::Env &env, Genode::Heap &heap) : env(env), heap(heap) {} - - Block::Driver *create() - { - driver = new (&heap) ::Driver(env, heap); - return driver; - } - - void destroy(Block::Driver *driver) { - Genode::destroy(&heap, static_cast<::Driver*>(driver)); } - }; - - void resource_handler() { } - - Genode::Env &env; - Genode::Heap heap { env.ram(), env.rm() }; - Factory factory { env, heap }; - Block::Root root { env.ep(), heap, env.rm(), factory, true }; - Genode::Signal_handler
resource_dispatcher { - env.ep(), *this, &Main::resource_handler }; - - Main(Genode::Env &env) : env(env) - { - env.parent().announce(env.ep().manage(root)); - env.parent().resource_avail_sigh(resource_dispatcher); - } -}; - - -void Component::construct(Genode::Env &env) -{ - /* XXX execute constructors of global statics */ - env.exec_static_constructors(); - - static Main server(env); -} diff --git a/repos/os/src/server/block_cache/target.mk b/repos/os/src/server/block_cache/target.mk deleted file mode 100644 index 91f4548754..0000000000 --- a/repos/os/src/server/block_cache/target.mk +++ /dev/null @@ -1,5 +0,0 @@ -TARGET = block_cache -LIBS = base -SRC_CC = main.cc lru.cc - -CC_CXX_WARN_STRICT =