Remove unused vfs_replay component

Fixes #5493
This commit is contained in:
Norman Feske 2025-03-27 12:38:39 +01:00
parent 7187499133
commit 37ec1db5ea
2 changed files with 0 additions and 534 deletions

View File

@ -1,531 +0,0 @@
/*
* \brief VFS replay tool
* \author Josef Soentgen
* \date 2020-03-18
*/
/*
* Copyright (C) 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.
*/
#include <base/attached_ram_dataspace.h>
#include <base/attached_rom_dataspace.h>
#include <base/component.h>
#include <base/heap.h>
#include <util/string.h>
#include <vfs/simple_env.h>
#include <vfs/file_system_factory.h>
#include <vfs/dir_file_system.h>
using namespace Genode;
using Vfs::file_offset;
using Vfs::file_size;
class Vfs_replay
{
private:
Vfs_replay(const Vfs_replay&) = delete;
Vfs_replay& operator=(const Vfs_replay&) = delete;
Env &_env;
Vfs::File_system &_vfs;
Vfs::Env::Io &_io;
Vfs::Vfs_handle *_vfs_handle;
Attached_ram_dataspace _write_buffer;
Attached_ram_dataspace _read_buffer;
bool _verbose;
Xml_node _replay_node;
Xml_node _request_node { "<empty/>" };
size_t _num_requests { 0 };
unsigned _curr_request_id { 0 };
bool _finished { false };
struct Request
{
enum Type { INVALID, READ, WRITE, SYNC, };
static char const *type_to_string(Type t)
{
switch (t) {
case Type::INVALID: return "INVALID";
case Type::READ: return "READ";
case Type::WRITE: return "WRITE";
case Type::SYNC: return "SYNC";
}
return "<unknown>";
}
enum State {
NONE,
READ_PENDING, READ_IN_PROGRESS, READ_COMPLETE,
WRITE_PENDING, WRITE_IN_PROGRESS, WRITE_COMPLETE,
SYNC_PENDING, SYNC_IN_PROGRESS, SYNC_COMPLETE,
ERROR,
};
static char const *state_to_string(State s)
{
switch (s) {
case State::NONE: return "NONE";
case State::READ_PENDING: return "READ_PENDING";
case State::READ_IN_PROGRESS: return "READ_IN_PROGRESS";
case State::READ_COMPLETE: return "READ_COMPLETE";
case State::WRITE_PENDING: return "WRITE_PENDING";
case State::WRITE_IN_PROGRESS: return "WRITE_IN_PROGRESS";
case State::WRITE_COMPLETE: return "WRITE_COMPLETE";
case State::SYNC_PENDING: return "SYNC_PENDING";
case State::SYNC_IN_PROGRESS: return "SYNC_IN_PROGRESS";
case State::SYNC_COMPLETE: return "SYNC_COMPLETE";
case State::ERROR: return "ERROR";
}
return "<unknown>";
}
Type type;
State state;
file_offset offset;
size_t count;
size_t out_count;
file_offset current_offset;
size_t current_count;
bool success;
bool complete;
bool pending() const { return state != NONE; }
bool idle() const { return state == NONE; }
void print(Genode::Output &out) const
{
Genode::print(out, "[ type: ", type_to_string(type),
" state: ", state_to_string(state),
" offset: ", offset,
" count: ", count,
" out_count: ", out_count,
" current_offset: ", current_offset,
" current_count: ", current_count,
" success: ", success,
" complete: ", complete, " ]");
}
};
static Request::Type string_to_type(char const *string)
{
enum { READ_LEN = 4, WRITE_LEN = 5, SYNC_LEN = 4, };
if (Genode::strcmp(string, "read", READ_LEN) == 0) {
return Request::Type::READ;
} else
if (Genode::strcmp(string, "write", WRITE_LEN) == 0) {
return Request::Type::WRITE;
} else
if (Genode::strcmp(string, "sync", SYNC_LEN) == 0) {
return Request::Type::SYNC;
} else
return Request::Type::INVALID;
}
Request _current_request { };
bool _read(Request &request)
{
bool progress = false;
switch (request.state) {
case Request::State::NONE:
if (request.count > _read_buffer.size()) {
struct Buffer_too_small { };
throw Buffer_too_small ();
}
request.state = Request::State::READ_PENDING;
progress = true;
[[fallthrough]];
case Request::State::READ_PENDING:
_vfs_handle->seek(request.current_offset);
if (!_vfs_handle->fs().queue_read(_vfs_handle, request.current_count)) {
return progress;
}
request.state = Request::State::READ_IN_PROGRESS;
progress = true;
[[fallthrough]];
case Request::State::READ_IN_PROGRESS:
{
using Result = Vfs::File_io_service::Read_result;
bool completed = false;
size_t out = 0;
Byte_range_ptr const dst(_read_buffer.local_addr<char>(),
request.current_count);
Result const result =
_vfs_handle->fs().complete_read(_vfs_handle, dst, out);
if (result == Result::READ_QUEUED
|| result == Result::READ_ERR_WOULD_BLOCK) {
return progress;
}
if (result == Result::READ_OK) {
request.current_offset += out;
request.current_count -= out;
request.success = true;
} else
if ( result == Result::READ_ERR_IO
|| result == Result::READ_ERR_INVALID) {
request.success = false;
completed = true;
}
if (request.current_count == 0 || completed) {
request.state = Request::State::READ_COMPLETE;
} else {
request.state = Request::State::READ_PENDING;
return progress;
}
progress = true;
}
[[fallthrough]];
case Request::State::READ_COMPLETE:
request.state = Request::State::NONE;
request.complete = true;
progress = true;
default: break;
}
return progress;
}
bool _write(Request &request)
{
bool progress = false;
switch (request.state) {
case Request::State::NONE:
if (request.count > _write_buffer.size()) {
struct Buffer_too_small { };
throw Buffer_too_small ();
}
request.state = Request::State::WRITE_PENDING;
progress = true;
[[fallthrough]];
case Request::State::WRITE_PENDING:
_vfs_handle->seek(request.current_offset);
request.state = Request::State::WRITE_IN_PROGRESS;
progress = true;
[[fallthrough]];
case Request::State::WRITE_IN_PROGRESS:
{
using Result = Vfs::File_io_service::Write_result;
bool completed = false;
size_t out = 0;
Const_byte_range_ptr const src(_write_buffer.local_addr<char>(),
request.current_count);
Result const result = _vfs_handle->fs().write(_vfs_handle, src, out);
switch (result) {
case Result::WRITE_ERR_WOULD_BLOCK:
return progress;
case Result::WRITE_OK:
request.current_offset += out;
request.current_count -= out;
request.success = true;
break;
case Result::WRITE_ERR_IO:
case Result::WRITE_ERR_INVALID:
request.success = false;
completed = true;
break;
}
if (request.current_count == 0 || completed) {
request.state = Request::State::WRITE_COMPLETE;
} else {
request.state = Request::State::WRITE_PENDING;
return progress;
}
progress = true;
}
[[fallthrough]];
case Request::State::WRITE_COMPLETE:
request.state = Request::State::NONE;
request.complete = true;
progress = true;
default: break;
}
return progress;
}
bool _sync(Request &request)
{
bool progress = false;
switch (request.state) {
case Request::State::NONE:
request.state = Request::State::SYNC_PENDING;
progress = true;
[[fallthrough]];
case Request::State::SYNC_PENDING:
if (!_vfs_handle->fs().queue_sync(_vfs_handle)) {
return progress;
}
request.state = Request::State::SYNC_IN_PROGRESS;
progress = true;
[[fallthrough]];
case Request::State::SYNC_IN_PROGRESS:
{
using Result = Vfs::File_io_service::Sync_result;
Result const result = _vfs_handle->fs().complete_sync(_vfs_handle);
if (result == Result::SYNC_QUEUED) {
return progress;
}
if (result == Result::SYNC_ERR_INVALID) {
request.success = false;
}
if (result == Result::SYNC_OK) {
request.success = true;
}
request.state = Request::State::SYNC_COMPLETE;
progress = true;
}
[[fallthrough]];
case Request::State::SYNC_COMPLETE:
request.state = Request::State::NONE;
request.complete = true;
progress = true;
default: break;
}
return progress;
}
bool _handle_request(Genode::Xml_node const &node)
{
if (!_current_request.pending()) {
file_offset const offset = node.attribute_value("offset", file_size(~0llu));
size_t const count = node.attribute_value("count", ~0lu);
using Type_String = String<16>;
Type_String const type_string = node.attribute_value("type", Type_String());
Request::Type const type = string_to_type(type_string.string());
_current_request.type = type;
if (type != Request::Type::INVALID) {
_current_request = {
.type = type,
.state = Request::State::NONE,
.offset = offset,
.count = count,
.out_count = 0,
.current_offset = offset,
.current_count = count,
.success = false,
.complete = false,
};
if (_verbose) {
log("Next request: id: ", _curr_request_id, " ",
_current_request);
}
}
}
switch (_current_request.type) {
case Request::Type::READ:
return _read(_current_request);
case Request::Type::WRITE:
return _write(_current_request);
case Request::Type::SYNC:
return _sync(_current_request);
case Request::Type::INVALID:
_current_request.complete = true;
return true;
}
return false;
}
void _process_replay()
{
bool failed = false;
while (true) {
bool const progress = _handle_request(_request_node);
if (!progress) { break; }
if (_current_request.complete) {
if (_verbose) {
log("Completed request: ", _current_request);
}
if (!_current_request.success) {
error("current request: ", _current_request, " failed");
failed = true;
_finished = true;
break;
}
try {
_request_node = _replay_node.sub_node(++_curr_request_id);
} catch (Xml_node::Nonexistent_sub_node) {
_finished = true;
break;
}
}
}
if (_finished) {
_env.parent().exit(failed ? 1 : 0);
}
_io.commit();
}
public:
Vfs_replay(Env &env, Vfs::File_system &vfs, Vfs::Env::Io &io,
Xml_node const & config)
:
_env { env },
_vfs { vfs },
_io { io },
_vfs_handle { nullptr },
_write_buffer { _env.ram(), _env.rm(),
config.attribute_value("write_buffer_size", 1u << 20) },
_read_buffer { _env.ram(), _env.rm(),
config.attribute_value("read_buffer_size", 1u << 20) },
_verbose { config.attribute_value("verbose", false) },
_replay_node { config.sub_node("replay") }
{
Genode::memset(_write_buffer.local_addr<char>(), 0x55,
_write_buffer.size());
}
void kick_off(Genode::Allocator &alloc, char const *file)
{
using Open_result = Vfs::Directory_service::Open_result;
Open_result res = _vfs.open(file,
Vfs::Directory_service::OPEN_MODE_RDWR,
&_vfs_handle, alloc);
if (res != Open_result::OPEN_OK) {
throw Genode::Exception();
}
_current_request = {
.type = Request::Type::INVALID,
.state = Request::State::NONE,
.offset = 0,
.count = 0,
.out_count = 0,
.current_offset = 0,
.current_count = 0,
.success = false,
.complete = false,
};
_num_requests = _replay_node.num_sub_nodes();
_request_node = _replay_node.sub_node(_curr_request_id);
_process_replay();
}
void io_progress_response_handler()
{
/* ignore any out-standing signal */
if (_finished) { return; }
_process_replay();
}
};
struct Main : private Genode::Entrypoint::Io_progress_handler,
private Vfs::Env::User
{
Genode::Env &_env;
Genode::Heap _heap { _env.ram(), _env.rm() };
Genode::Attached_rom_dataspace _config_rom { _env, "config" };
Vfs::Simple_env _vfs_env { _env, _heap, _config_rom.xml().sub_node("vfs"), *this };
Genode::Signal_handler<Main> _reactivate_handler {
_env.ep(), *this, &Main::handle_io_progress };
Vfs_replay _replay { _env, _vfs_env.root_dir(), _vfs_env.io(), _config_rom.xml() };
/**
* Vfs::Env::User interface
*/
void wakeup_vfs_user() override { _reactivate_handler.local_submit(); }
Main(Genode::Env &env) : _env { env }
{
using File_name = Genode::String<64>;
File_name const file_name =
_config_rom.xml().attribute_value("file", File_name());
if (!file_name.valid()) {
Genode::error("config 'file' attribute invalid");
throw Genode::Exception();
}
_env.ep().register_io_progress_handler(*this);
_replay.kick_off(_heap, file_name.string());
handle_io_progress();
}
void handle_io_progress() override
{
_replay.io_progress_response_handler();
}
};
void Component::construct(Genode::Env &env)
{
static Main main(env);
}

View File

@ -1,3 +0,0 @@
TARGET = tresor_vfs_replay
SRC_CC = component.cc
LIBS = base vfs