cached_fs_rom: path for symlink traversal
parent
2132b41ab9
commit
8dd6e9c248
|
@ -0,0 +1,783 @@
|
|||
From e65583c3e9cf0e9c326bb2d414d40fa32f64f9c6 Mon Sep 17 00:00:00 2001
|
||||
From: Emery Hemingway <ehmry@posteo.net>
|
||||
Date: Tue, 3 Nov 2020 15:28:56 +0100
|
||||
Subject: [PATCH 1/3] cached_fs_rom: resolve symlinks
|
||||
|
||||
Follow symlinks from ROM requests to files. This complicates the
|
||||
implementation but allows ROM requests to be redirected at both the
|
||||
label routing and the file-system layers. Redirecting ROMs with symlinks
|
||||
is useful for retrieving ROMs from deeply nested or otherwise
|
||||
excessively long file-system paths.
|
||||
---
|
||||
repos/os/src/server/cached_fs_rom/main.cc | 472 +++++++++++++---------
|
||||
1 file changed, 281 insertions(+), 191 deletions(-)
|
||||
|
||||
diff --git a/repos/os/src/server/cached_fs_rom/main.cc b/repos/os/src/server/cached_fs_rom/main.cc
|
||||
index 9e4e4d0eee..bac2c075a9 100755
|
||||
--- a/repos/os/src/server/cached_fs_rom/main.cc
|
||||
+++ b/repos/os/src/server/cached_fs_rom/main.cc
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
- * Copyright (C) 2018 Genode Labs GmbH
|
||||
+ * Copyright (C) 2018-2020 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.
|
||||
@@ -26,32 +26,119 @@
|
||||
/* local session-requests utility */
|
||||
#include "session_requests.h"
|
||||
|
||||
-/*****************
|
||||
- ** ROM service **
|
||||
- *****************/
|
||||
|
||||
namespace Cached_fs_rom {
|
||||
|
||||
using namespace Genode;
|
||||
- typedef Genode::Path<File_system::MAX_PATH_LEN> Path;
|
||||
- typedef File_system::Session_client::Tx::Source Tx_source;
|
||||
-
|
||||
- struct Cached_rom;
|
||||
- typedef Genode::Id_space<Cached_rom> Cache_space;
|
||||
|
||||
struct Transfer;
|
||||
typedef Genode::Id_space<Transfer> Transfer_space;
|
||||
|
||||
+ struct Cached_rom;
|
||||
+ typedef Genode::Id_space<Cached_rom> Cache_space;
|
||||
+
|
||||
class Session_component;
|
||||
typedef Genode::Id_space<Session_component> Session_space;
|
||||
|
||||
struct Main;
|
||||
|
||||
+ typedef Genode::Path<File_system::MAX_PATH_LEN> Path;
|
||||
+ typedef File_system::Session_client::Tx::Source Tx_source;
|
||||
typedef File_system::Session::Tx::Source::Packet_alloc_failed Packet_alloc_failed;
|
||||
- typedef File_system::File_handle File_handle;
|
||||
}
|
||||
|
||||
|
||||
+/**
|
||||
+ * State of symlink resolution and file reading
|
||||
+ */
|
||||
+struct Cached_fs_rom::Transfer final
|
||||
+{
|
||||
+ Transfer_space &_transfers;
|
||||
+ File_system::Session &_fs;
|
||||
+
|
||||
+ Path const first_path;
|
||||
+ Path final_path = first_path;
|
||||
+
|
||||
+ Reconstructible<Transfer_space::Element> _transfer_elem {
|
||||
+ *this, _transfers,
|
||||
+ Transfer_space::Id{_fs.node(first_path.string()).value}
|
||||
+ };
|
||||
+
|
||||
+ File_system::Packet_descriptor _raw_pkt = _alloc_packet();
|
||||
+ File_system::Packet_guard _packet_guard { *_fs.tx(), _raw_pkt };
|
||||
+
|
||||
+ Attached_ram_dataspace ram_ds;
|
||||
+ File_system::Status status { };
|
||||
+
|
||||
+ /* Id of the originating session request */
|
||||
+ Parent::Server::Id const request_id;
|
||||
+
|
||||
+ File_system::seek_off_t seek = 0;
|
||||
+
|
||||
+ bool diag;
|
||||
+ bool completed = false;
|
||||
+
|
||||
+ /**
|
||||
+ * Allocate space in the File_system packet buffer
|
||||
+ *
|
||||
+ * \throw Packet_alloc_failed
|
||||
+ */
|
||||
+ File_system::Packet_descriptor _alloc_packet()
|
||||
+ {
|
||||
+ if (!_fs.tx()->ready_to_submit())
|
||||
+ throw Packet_alloc_failed();
|
||||
+
|
||||
+ size_t chunk_size = max(
|
||||
+ size_t(File_system::MAX_PATH_LEN),
|
||||
+ _fs.tx()->bulk_buffer_size()/4);
|
||||
+ return _fs.tx()->alloc_packet(chunk_size);
|
||||
+ }
|
||||
+
|
||||
+ File_system::Node_handle handle() const {
|
||||
+ return File_system::Node_handle{ _transfer_elem->id().value }; }
|
||||
+
|
||||
+ void replace_handle(File_system::Node_handle new_handle)
|
||||
+ {
|
||||
+ _fs.close(handle());
|
||||
+ _transfer_elem.destruct();
|
||||
+ _transfer_elem.construct(
|
||||
+ *this, _transfers, Transfer_space::Id{new_handle.value});
|
||||
+ }
|
||||
+
|
||||
+ Transfer(Genode::Env &env,
|
||||
+ File_system::Session &fs,
|
||||
+ Transfer_space &space,
|
||||
+ Path path,
|
||||
+ Parent::Server::Id &pid,
|
||||
+ bool diag)
|
||||
+ : _transfers(space)
|
||||
+ , _fs(fs)
|
||||
+ , first_path(path)
|
||||
+ , ram_ds(env.ram(), env.rm(), 0)
|
||||
+ , request_id(pid)
|
||||
+ , diag(diag)
|
||||
+ { }
|
||||
+
|
||||
+ ~Transfer() { _fs.close(handle()); }
|
||||
+
|
||||
+ bool matches(Path const &path) const {
|
||||
+ return (first_path == path || final_path == path); }
|
||||
+
|
||||
+ void submit_next_packet()
|
||||
+ {
|
||||
+ File_system::Packet_descriptor packet(
|
||||
+ _raw_pkt, handle(),
|
||||
+ File_system::Packet_descriptor::READ,
|
||||
+ _raw_pkt.size(), seek);
|
||||
+ _fs.tx()->submit_packet(packet);
|
||||
+ }
|
||||
+
|
||||
+};
|
||||
+
|
||||
+
|
||||
+/**
|
||||
+ * A dataspace corresponding to a file-system path
|
||||
+ */
|
||||
struct Cached_fs_rom::Cached_rom final
|
||||
{
|
||||
Cached_rom(Cached_rom const &);
|
||||
@@ -60,20 +147,15 @@ struct Cached_fs_rom::Cached_rom final
|
||||
Genode::Env &env;
|
||||
Rm_connection &rm_connection;
|
||||
|
||||
- size_t const file_size;
|
||||
-
|
||||
/**
|
||||
* Backing RAM dataspace
|
||||
- *
|
||||
- * This shall be valid even if the file is empty.
|
||||
*/
|
||||
- Attached_ram_dataspace ram_ds {
|
||||
- env.pd(), env.rm(), file_size ? file_size : 1 };
|
||||
+ Attached_ram_dataspace ram_ds { env.pd(), env.rm(), 0 };
|
||||
|
||||
/**
|
||||
* Read-only region map exposed as ROM module to the client
|
||||
*/
|
||||
- Region_map_client rm { rm_connection.create(ram_ds.size()) };
|
||||
+ Region_map_client rm_client;
|
||||
Region_map::Local_addr rm_attachment { };
|
||||
Dataspace_capability rm_ds { };
|
||||
|
||||
@@ -81,48 +163,39 @@ struct Cached_fs_rom::Cached_rom final
|
||||
|
||||
Cache_space::Element cache_elem;
|
||||
|
||||
- Transfer *transfer = nullptr;
|
||||
-
|
||||
/**
|
||||
* Reference count of cache entry
|
||||
*/
|
||||
int _ref_count = 0;
|
||||
|
||||
- Cached_rom(Cache_space &cache_space,
|
||||
- Env &env,
|
||||
- Rm_connection &rm,
|
||||
- Path const &file_path,
|
||||
- size_t size)
|
||||
- :
|
||||
- env(env), rm_connection(rm), file_size(size),
|
||||
- path(file_path),
|
||||
- cache_elem(*this, cache_space)
|
||||
+ Cached_rom(Genode::Env &env,
|
||||
+ Rm_connection &rm,
|
||||
+ Cache_space &cache_space,
|
||||
+ Transfer &transfer)
|
||||
+ : env(env)
|
||||
+ , rm_connection(rm)
|
||||
+ , rm_client(rm.create(transfer.ram_ds.size()))
|
||||
+ , path(transfer.final_path)
|
||||
+ , cache_elem(*this, cache_space)
|
||||
{
|
||||
- if (size == 0)
|
||||
- complete();
|
||||
+ /* move dataspace from the transfer object */
|
||||
+ transfer.ram_ds.swap(ram_ds);
|
||||
+
|
||||
+ /* attach dataspace read-only into region map */
|
||||
+ enum { OFFSET = 0, LOCAL_ADDR = false, EXEC = true, WRITE = false };
|
||||
+ rm_attachment = rm_client.attach(
|
||||
+ ram_ds.cap(), ram_ds.size(), OFFSET,
|
||||
+ LOCAL_ADDR, (addr_t)~0, EXEC, WRITE);
|
||||
+ rm_ds = rm_client.dataspace();
|
||||
}
|
||||
|
||||
- /**
|
||||
- * Destructor
|
||||
- */
|
||||
~Cached_rom()
|
||||
{
|
||||
if (rm_attachment)
|
||||
- rm.detach(rm_attachment);
|
||||
+ rm_client.detach(rm_attachment);
|
||||
}
|
||||
|
||||
- bool completed() const { return rm_ds.valid(); }
|
||||
- bool unused() const { return (_ref_count < 1); }
|
||||
-
|
||||
- void complete()
|
||||
- {
|
||||
- /* attach dataspace read-only into region map */
|
||||
- enum { OFFSET = 0, LOCAL_ADDR = false, EXEC = true, WRITE = false };
|
||||
- rm_attachment = rm.attach(
|
||||
- ram_ds.cap(), ram_ds.size(), OFFSET,
|
||||
- LOCAL_ADDR, (addr_t)~0, EXEC, WRITE);
|
||||
- rm_ds = rm.dataspace();
|
||||
- }
|
||||
+ bool unused() const { return (_ref_count < 1); }
|
||||
|
||||
/**
|
||||
* Return dataspace with content of file
|
||||
@@ -130,6 +203,9 @@ struct Cached_fs_rom::Cached_rom final
|
||||
Rom_dataspace_capability dataspace() const {
|
||||
return static_cap_cast<Rom_dataspace>(rm_ds); }
|
||||
|
||||
+ /**
|
||||
+ * Guard for maintaining reference count
|
||||
+ */
|
||||
struct Guard
|
||||
{
|
||||
Cached_rom &_rom;
|
||||
@@ -142,97 +218,6 @@ struct Cached_fs_rom::Cached_rom final
|
||||
};
|
||||
|
||||
|
||||
-struct Cached_fs_rom::Transfer final
|
||||
-{
|
||||
- Cached_rom &_cached_rom;
|
||||
- Cached_rom::Guard _cache_guard { _cached_rom };
|
||||
-
|
||||
- File_system::Session &_fs;
|
||||
- File_system::File_handle _handle;
|
||||
-
|
||||
- File_system::file_size_t const _size;
|
||||
- File_system::seek_off_t _seek = 0;
|
||||
- File_system::Packet_descriptor _raw_pkt = _alloc_packet();
|
||||
- File_system::Packet_guard _packet_guard { *_fs.tx(), _raw_pkt };
|
||||
-
|
||||
- Transfer_space::Element _transfer_elem;
|
||||
-
|
||||
- /**
|
||||
- * Allocate space in the File_system packet buffer
|
||||
- *
|
||||
- * \throw Packet_alloc_failed
|
||||
- */
|
||||
- File_system::Packet_descriptor _alloc_packet()
|
||||
- {
|
||||
- if (!_fs.tx()->ready_to_submit())
|
||||
- throw Packet_alloc_failed();
|
||||
-
|
||||
- size_t chunk_size = min(_size, _fs.tx()->bulk_buffer_size()/4);
|
||||
- return _fs.tx()->alloc_packet(chunk_size);
|
||||
- }
|
||||
-
|
||||
- void _submit_next_packet()
|
||||
- {
|
||||
- using namespace File_system;
|
||||
-
|
||||
- File_system::Packet_descriptor
|
||||
- packet(_raw_pkt, _handle,
|
||||
- File_system::Packet_descriptor::READ,
|
||||
- _raw_pkt.size(), _seek);
|
||||
-
|
||||
- _fs.tx()->submit_packet(packet);
|
||||
- }
|
||||
-
|
||||
- public:
|
||||
-
|
||||
- /**
|
||||
- * Constructor
|
||||
- */
|
||||
- Transfer(Transfer_space &space,
|
||||
- Cached_rom &rom,
|
||||
- File_system::Session &fs,
|
||||
- File_system::File_handle file_handle,
|
||||
- size_t file_size)
|
||||
- :
|
||||
- _cached_rom(rom), _fs(fs),
|
||||
- _handle(file_handle), _size(file_size),
|
||||
- _transfer_elem(*this, space, Transfer_space::Id{_handle.value})
|
||||
- {
|
||||
- _cached_rom.transfer = this;
|
||||
-
|
||||
- _submit_next_packet();
|
||||
- }
|
||||
-
|
||||
- Path const &path() const { return _cached_rom.path; }
|
||||
-
|
||||
- bool completed() const { return (_seek >= _size); }
|
||||
-
|
||||
- /**
|
||||
- * Called from the packet signal handler.
|
||||
- */
|
||||
- void process_packet(File_system::Packet_descriptor const packet)
|
||||
- {
|
||||
- auto const pkt_seek = packet.position();
|
||||
-
|
||||
- if (pkt_seek > _seek || _seek >= _size) {
|
||||
- error("bad packet seek position for ", path());
|
||||
- error("packet seek is ", packet.position(), ", file seek is ", _seek, ", file size is ", _size);
|
||||
- _seek = _size;
|
||||
- } else {
|
||||
- size_t const n = min(packet.length(), _size - pkt_seek);
|
||||
- memcpy(_cached_rom.ram_ds.local_addr<char>()+pkt_seek,
|
||||
- _fs.tx()->packet_content(packet), n);
|
||||
- _seek = pkt_seek+n;
|
||||
- }
|
||||
-
|
||||
- if (completed())
|
||||
- _cached_rom.complete();
|
||||
- else
|
||||
- _submit_next_packet();
|
||||
- }
|
||||
-};
|
||||
-
|
||||
-
|
||||
class Cached_fs_rom::Session_component final : public Rpc_object<Rom_session>
|
||||
{
|
||||
private:
|
||||
@@ -240,17 +225,15 @@ class Cached_fs_rom::Session_component final : public Rpc_object<Rom_session>
|
||||
Cached_rom &_cached_rom;
|
||||
Cached_rom::Guard _cache_guard { _cached_rom };
|
||||
Session_space::Element _sessions_elem;
|
||||
- Session_label const _label;
|
||||
|
||||
public:
|
||||
|
||||
Session_component(Cached_rom &cached_rom,
|
||||
- Session_space &space, Session_space::Id id,
|
||||
- Session_label const &label)
|
||||
+ Session_space &space,
|
||||
+ Parent::Server::Id pid)
|
||||
:
|
||||
_cached_rom(cached_rom),
|
||||
- _sessions_elem(*this, space, id),
|
||||
- _label(label)
|
||||
+ _sessions_elem(*this, space, Session_space::Id{pid.value})
|
||||
{ }
|
||||
|
||||
|
||||
@@ -273,8 +256,8 @@ struct Cached_fs_rom::Main final : Genode::Session_request_handler
|
||||
|
||||
Rm_connection rm { env };
|
||||
|
||||
- Cache_space cache { };
|
||||
Transfer_space transfers { };
|
||||
+ Cache_space cache { };
|
||||
Session_space sessions { };
|
||||
|
||||
Heap heap { env.pd(), env.rm() };
|
||||
@@ -302,36 +285,133 @@ struct Cached_fs_rom::Main final : Genode::Session_request_handler
|
||||
return (bool)discard;
|
||||
}
|
||||
|
||||
- /**
|
||||
- * Open a file handle
|
||||
- */
|
||||
- File_system::File_handle open(Path const &file_path)
|
||||
+ void resolve(Transfer &transfer)
|
||||
{
|
||||
using namespace File_system;
|
||||
+ transfer.status = fs.status(transfer.handle());
|
||||
|
||||
- Path dir_path(file_path);
|
||||
- dir_path.strip_last_element();
|
||||
- Path file_name(file_path);
|
||||
- file_name.keep_only_last_element();
|
||||
+ if (transfer.status.directory()) {
|
||||
+ error("cannot serve directory as ROM, \"", transfer.final_path, "\"");
|
||||
+ throw Service_denied();
|
||||
+ }
|
||||
|
||||
+ Path dir_path(transfer.final_path);
|
||||
+ dir_path.strip_last_element();
|
||||
Dir_handle parent_handle = fs.dir(dir_path.base(), false);
|
||||
Handle_guard parent_guard(fs, parent_handle);
|
||||
|
||||
- return fs.file(
|
||||
- parent_handle, file_name.base() + 1,
|
||||
- File_system::READ_ONLY, false);
|
||||
+ if (transfer.status.symlink()) {
|
||||
+ Symlink_handle link_handle = fs.symlink(
|
||||
+ parent_handle, transfer.final_path.last_element(), false);
|
||||
+ transfer.replace_handle(link_handle);
|
||||
+ } else {
|
||||
+ File_handle file_handle = fs.file(
|
||||
+ parent_handle, transfer.final_path.last_element(), READ_ONLY, false);
|
||||
+ transfer.replace_handle(file_handle);
|
||||
+
|
||||
+ /* allocate a backing dataspace */
|
||||
+ size_t ds_size =
|
||||
+ align_addr(max(transfer.status.size, 1U), 12);
|
||||
+
|
||||
+ while (env.pd().avail_ram().value < ds_size
|
||||
+ || env.pd().avail_caps().value < 8) {
|
||||
+ /* drop unused cache entries */
|
||||
+ if (!cache_evict()) break;
|
||||
+ }
|
||||
+
|
||||
+ transfer.ram_ds.realloc(&env.ram(), ds_size);
|
||||
+ }
|
||||
+
|
||||
+ transfer.submit_next_packet();
|
||||
}
|
||||
|
||||
/**
|
||||
- * Open a file with some exception management
|
||||
+ * Called from the packet signal handler.
|
||||
*/
|
||||
- File_system::File_handle try_open(Path const &file_path)
|
||||
+ void process_packet(Transfer &transfer,
|
||||
+ File_system::Packet_descriptor const packet)
|
||||
+ {
|
||||
+ if (transfer.status.symlink()) {
|
||||
+ size_t const n = packet.length();
|
||||
+ if (n >= Path::capacity()) {
|
||||
+ error("bad symlink read at ", transfer.final_path);
|
||||
+ throw Service_denied();
|
||||
+ }
|
||||
+
|
||||
+ char buf[Path::capacity()];
|
||||
+ copy_cstring(buf, fs.tx()->packet_content(packet), n);
|
||||
+ if (*buf == '/')
|
||||
+ transfer.final_path = Path(buf);
|
||||
+ else
|
||||
+ transfer.final_path.append_element(buf);
|
||||
+
|
||||
+ if (transfer.diag)
|
||||
+ log("following \"", transfer.first_path, "\" to \"", transfer.final_path, "\"");
|
||||
+
|
||||
+ /* lookup the link target in the cache */
|
||||
+ cache.for_each<Cached_rom&>([&] (Cached_rom &rom) {
|
||||
+ if (!transfer.completed && rom.path == transfer.final_path) {
|
||||
+ /*
|
||||
+ * this session can be served but future requests to
|
||||
+ * first_path must again traverse the symlinks to final_path
|
||||
+ */
|
||||
+ Session_component *session = new (heap)
|
||||
+ Session_component(rom, sessions, transfer.request_id);
|
||||
+ if (transfer.diag)
|
||||
+ log("deliver cached \"", transfer.final_path, "\"");
|
||||
+ env.parent().deliver_session_cap(
|
||||
+ transfer.request_id, env.ep().manage(*session));
|
||||
+ transfer.completed = true;
|
||||
+ }
|
||||
+ });
|
||||
+ if (transfer.completed) {
|
||||
+ destroy(heap, &transfer);
|
||||
+ } else {
|
||||
+ transfer.replace_handle(fs.node(transfer.final_path.string()));
|
||||
+ resolve(transfer);
|
||||
+ }
|
||||
+ } else {
|
||||
+ auto const pkt_seek = packet.position();
|
||||
+
|
||||
+ if (pkt_seek > transfer.seek || transfer.seek >= transfer.status.size) {
|
||||
+ error("unexpected packet seek position for ", transfer.final_path);
|
||||
+ error("packet seek is ", packet.position(), ", file seek is ", transfer.seek, ", file size is ", transfer.status.size);
|
||||
+ transfer.seek = transfer.status.size;
|
||||
+ } else {
|
||||
+ size_t const n = min(packet.length(), transfer.status.size - pkt_seek);
|
||||
+ memcpy(transfer.ram_ds.local_addr<char>()+pkt_seek,
|
||||
+ fs.tx()->packet_content(packet), n);
|
||||
+ transfer.seek = pkt_seek+n;
|
||||
+ }
|
||||
+
|
||||
+ if (transfer.seek < transfer.status.size) {
|
||||
+ transfer.submit_next_packet();
|
||||
+ } else {
|
||||
+ Cached_rom *rom = new (heap)
|
||||
+ Cached_rom(env, rm, cache, transfer);
|
||||
+ destroy(heap, &transfer);
|
||||
+ Session_component *session = new (heap)
|
||||
+ Session_component(*rom, sessions, transfer.request_id);
|
||||
+ if (transfer.diag)
|
||||
+ log("deliver fresh \"", transfer.final_path, "\"");
|
||||
+ env.parent().deliver_session_cap(
|
||||
+ transfer.request_id, env.ep().manage(*session));
|
||||
+ session_requests.schedule();
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ /**
|
||||
+ * Attempt a procedure with exception management
|
||||
+ */
|
||||
+ template <typename PROC>
|
||||
+ void try_transfer(Path const &file_path, PROC const &proc)
|
||||
{
|
||||
using namespace File_system;
|
||||
- try { return open(file_path); }
|
||||
+ try { proc(); return; }
|
||||
catch (Lookup_failed) { error(file_path, " not found"); }
|
||||
catch (Invalid_handle) { error(file_path, ": invalid handle"); }
|
||||
- catch (Invalid_name) { error(file_path, ": invalid nme"); }
|
||||
+ catch (Invalid_name) { error(file_path, ": invalid name"); }
|
||||
catch (Permission_denied) { error(file_path, ": permission denied"); }
|
||||
catch (...) { error(file_path, ": unhandled error"); }
|
||||
throw Service_denied();
|
||||
@@ -364,55 +444,58 @@ struct Cached_fs_rom::Main final : Genode::Session_request_handler
|
||||
** Find ROM in cache **
|
||||
***********************/
|
||||
|
||||
- Session_space::Id const id { pid.value };
|
||||
-
|
||||
Session_label const label = label_from_args(args.string());
|
||||
Path const path(label.last_element().string());
|
||||
|
||||
- Cached_rom *rom = nullptr;
|
||||
+ bool diag = session_diag_from_args(args.string()).enabled;
|
||||
|
||||
/* lookup the ROM in the cache */
|
||||
+ Cached_rom *rom = nullptr;
|
||||
cache.for_each<Cached_rom&>([&] (Cached_rom &other) {
|
||||
if (!rom && other.path == path)
|
||||
rom = &other;
|
||||
});
|
||||
|
||||
- if (!rom) {
|
||||
- File_system::File_handle handle = try_open(path);
|
||||
- File_system::Handle_guard guard(fs, handle);
|
||||
- size_t file_size = fs.status(handle).size;
|
||||
-
|
||||
- while (env.pd().avail_ram().value < file_size || env.pd().avail_caps().value < 8) {
|
||||
- /* drop unused cache entries */
|
||||
- if (!cache_evict()) break;
|
||||
- }
|
||||
-
|
||||
- rom = new (heap) Cached_rom(cache, env, rm, path, file_size);
|
||||
- }
|
||||
-
|
||||
- if (rom->completed()) {
|
||||
+ if (rom) {
|
||||
/* Create new RPC object */
|
||||
Session_component *session = new (heap)
|
||||
- Session_component(*rom, sessions, id, label);
|
||||
- if (session_diag_from_args(args.string()).enabled)
|
||||
- log("deliver ROM \"", label, "\"");
|
||||
+ Session_component(*rom, sessions, pid);
|
||||
+ if (diag)
|
||||
+ log("deliver cached \"", path, "\" to \"", label, "\"");
|
||||
env.parent().deliver_session_cap(pid, env.ep().manage(*session));
|
||||
|
||||
- } else if (!rom->transfer) {
|
||||
- File_system::File_handle handle = try_open(path);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ /* find matching transfer */
|
||||
+ bool pending = false;
|
||||
+ transfers.for_each<Transfer&>([&] (Transfer &other) {
|
||||
+ /* symlink race? */
|
||||
+ pending |= other.matches(path);
|
||||
+ });
|
||||
+
|
||||
+ if (pending) /* wait until transfer completes */
|
||||
+ return;
|
||||
+
|
||||
+ if (diag)
|
||||
+ log("lookup \"", path, "\" for \"", label, "\"");
|
||||
|
||||
+ /* initiate new transfer or throw Service_denied */
|
||||
+ try_transfer(path, [&] () {
|
||||
try {
|
||||
- new (heap) Transfer(transfers, *rom, fs, handle, rom->file_size);
|
||||
- }
|
||||
- catch (...) {
|
||||
- Genode::warning("defer transfer of ", rom->path);
|
||||
- fs.close(handle);
|
||||
- /* retry when next pending transfer completes */
|
||||
+ Transfer *transfer = new (heap)
|
||||
+ Transfer(env, fs, transfers, path, pid, diag);
|
||||
+ resolve(*transfer);
|
||||
+ } catch (Packet_alloc_failed) {
|
||||
+ /* temporary failure */
|
||||
return;
|
||||
}
|
||||
- }
|
||||
+ });
|
||||
}
|
||||
|
||||
+ /**
|
||||
+ * Destroy a closed session component
|
||||
+ */
|
||||
void handle_session_close(Parent::Server::Id pid) override
|
||||
{
|
||||
Session_space::Id id { pid.value };
|
||||
@@ -425,6 +508,9 @@ struct Cached_fs_rom::Main final : Genode::Session_request_handler
|
||||
});
|
||||
}
|
||||
|
||||
+ /**
|
||||
+ * Handle pending READ packets
|
||||
+ */
|
||||
void handle_packets()
|
||||
{
|
||||
Tx_source &source = *fs.tx();
|
||||
@@ -439,12 +525,16 @@ struct Cached_fs_rom::Main final : Genode::Session_request_handler
|
||||
transfers.apply<Transfer&>(
|
||||
Transfer_space::Id{pkt.handle().value}, [&] (Transfer &transfer)
|
||||
{
|
||||
- transfer.process_packet(pkt);
|
||||
- if (transfer.completed()) {
|
||||
- session_requests.schedule();
|
||||
+ stray_pkt = false;
|
||||
+ try {
|
||||
+ try_transfer(transfer.final_path, [&] () {
|
||||
+ process_packet(transfer, pkt);
|
||||
+ });
|
||||
+ } catch (Service_denied) {
|
||||
+ env.parent().session_response(
|
||||
+ transfer.request_id, Parent::SERVICE_DENIED);
|
||||
destroy(heap, &transfer);
|
||||
}
|
||||
- stray_pkt = false;
|
||||
});
|
||||
|
||||
if (stray_pkt)
|
||||
--
|
||||
2.28.0
|
||||
|
||||
|
||||
From 8e994fdb882071d224b1bb2b6efc711571b523f0 Mon Sep 17 00:00:00 2001
|
||||
From: Emery Hemingway <ehmry@posteo.net>
|
||||
Date: Tue, 3 Nov 2020 17:37:50 +0100
|
||||
Subject: [PATCH 2/3] cached_fs_rom: add directory session policy
|
||||
|
||||
Support for directing ROM requests into directories by policy.
|
||||
---
|
||||
repos/os/src/server/cached_fs_rom/README | 13 +++++++++++++
|
||||
repos/os/src/server/cached_fs_rom/main.cc | 17 ++++++++++++++++-
|
||||
2 files changed, 29 insertions(+), 1 deletion(-)
|
||||
create mode 100644 repos/os/src/server/cached_fs_rom/README
|
||||
|
||||
diff --git a/repos/os/src/server/cached_fs_rom/README b/repos/os/src/server/cached_fs_rom/README
|
||||
new file mode 100644
|
||||
index 0000000000..855c20ba7c
|
||||
--- /dev/null
|
||||
+++ b/repos/os/src/server/cached_fs_rom/README
|
||||
@@ -0,0 +1,13 @@
|
||||
+The 'cached_fs_rom' server is an alternative to 'fs_rom' for serving ROMs
|
||||
+of fixed-content. The server will cache file content between sessions and
|
||||
+clients, however the server does not cache intermediate symlinks.
|
||||
+
|
||||
+Configuration
|
||||
+~~~~~~~~~~~~~
|
||||
+
|
||||
+The only configuration option is the directory policy variable.
|
||||
+
|
||||
+! <config>
|
||||
+! <policy label_suffix=".lib.so" directory="rom/lib" />
|
||||
+! <default-policy directory="rom/bin" />
|
||||
+! </config>
|
||||
diff --git a/repos/os/src/server/cached_fs_rom/main.cc b/repos/os/src/server/cached_fs_rom/main.cc
|
||||
index bac2c075a9..8df3001111 100755
|
||||
--- a/repos/os/src/server/cached_fs_rom/main.cc
|
||||
+++ b/repos/os/src/server/cached_fs_rom/main.cc
|
||||
@@ -13,6 +13,7 @@
|
||||
|
||||
/* Genode includes */
|
||||
#include <os/path.h>
|
||||
+#include <os/session_policy.h>
|
||||
#include <file_system_session/connection.h>
|
||||
#include <file_system/util.h>
|
||||
#include <rom_session/rom_session.h>
|
||||
@@ -267,9 +268,14 @@ struct Cached_fs_rom::Main final : Genode::Session_request_handler
|
||||
|
||||
Session_requests_rom session_requests { env, *this };
|
||||
|
||||
+ Attached_rom_dataspace config_rom { env, "config" };
|
||||
+
|
||||
Io_signal_handler<Main> packet_handler {
|
||||
env.ep(), *this, &Main::handle_packets };
|
||||
|
||||
+ Signal_handler<Attached_rom_dataspace> config_handler {
|
||||
+ env.ep(), config_rom, &Attached_rom_dataspace::update };
|
||||
+
|
||||
/**
|
||||
* Return true when a cache element is freed
|
||||
*/
|
||||
@@ -444,8 +450,17 @@ struct Cached_fs_rom::Main final : Genode::Session_request_handler
|
||||
** Find ROM in cache **
|
||||
***********************/
|
||||
|
||||
+
|
||||
+ Path path("/");
|
||||
Session_label const label = label_from_args(args.string());
|
||||
- Path const path(label.last_element().string());
|
||||
+
|
||||
+ try {
|
||||
+ Session_policy policy(label, config_rom.xml());
|
||||
+ path.append(policy.attribute_value(
|
||||
+ "directory", String<Path::capacity()>("/")).string());
|
||||
+ } catch (Service_denied) { }
|
||||
+
|
||||
+ path.append_element(label.last_element().string());
|
||||
|
||||
bool diag = session_diag_from_args(args.string()).enabled;
|
||||
|
||||
--
|
||||
2.28.0
|
||||
|
||||
|
||||
From c98ba6fd70938804833e5c65a18d01c60f5be17f Mon Sep 17 00:00:00 2001
|
||||
From: Emery Hemingway <ehmry@posteo.net>
|
||||
Date: Thu, 5 Nov 2020 21:22:31 +0100
|
||||
Subject: [PATCH 3/3] cached_fs_rom: do not apply directory for absolute ROMs
|
||||
|
||||
If the ROM name starts with / then do not apply a directory policy.
|
||||
---
|
||||
repos/os/src/server/cached_fs_rom/main.cc | 15 ++++++++-------
|
||||
1 file changed, 8 insertions(+), 7 deletions(-)
|
||||
|
||||
diff --git a/repos/os/src/server/cached_fs_rom/main.cc b/repos/os/src/server/cached_fs_rom/main.cc
|
||||
index 8df3001111..4479b41e87 100755
|
||||
--- a/repos/os/src/server/cached_fs_rom/main.cc
|
||||
+++ b/repos/os/src/server/cached_fs_rom/main.cc
|
||||
@@ -450,17 +450,18 @@ struct Cached_fs_rom::Main final : Genode::Session_request_handler
|
||||
** Find ROM in cache **
|
||||
***********************/
|
||||
|
||||
+ Path path;
|
||||
|
||||
- Path path("/");
|
||||
- Session_label const label = label_from_args(args.string());
|
||||
+ auto const label = label_from_args(args.string());
|
||||
+ auto const rom_name = label.last_element();
|
||||
|
||||
try {
|
||||
Session_policy policy(label, config_rom.xml());
|
||||
- path.append(policy.attribute_value(
|
||||
- "directory", String<Path::capacity()>("/")).string());
|
||||
- } catch (Service_denied) { }
|
||||
-
|
||||
- path.append_element(label.last_element().string());
|
||||
+ auto dir = policy.attribute_value("directory", String<Path::capacity()>("/"));
|
||||
+ path = Path(rom_name.string(), dir.string());
|
||||
+ } catch (Service_denied) {
|
||||
+ path = Path(rom_name.string());
|
||||
+ }
|
||||
|
||||
bool diag = session_diag_from_args(args.string()).enabled;
|
||||
|
||||
--
|
||||
2.28.0
|
||||
|
|
@ -19,7 +19,7 @@ in {
|
|||
|
||||
acpi_drv = { };
|
||||
|
||||
cached_fs_rom = { };
|
||||
cached_fs_rom.patches = [ ./cached_fs_rom.patch ];
|
||||
|
||||
fb_sdl = with buildPackages; {
|
||||
nativeBuildInputs = [ pkgconfig ];
|
||||
|
|
Loading…
Reference in New Issue