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 =