mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-24 15:56:41 +00:00
Queued read/write/read_ready in VFS and servers
This commit is contained in:
parent
01daf19947
commit
61b6dccf13
@ -304,10 +304,17 @@ struct Libc::Pthreads
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
extern void (*libc_select_notify)();
|
||||||
|
|
||||||
struct Libc::Io_response_handler : Vfs::Io_response_handler
|
struct Libc::Io_response_handler : Vfs::Io_response_handler
|
||||||
{
|
{
|
||||||
void handle_io_response() override
|
void handle_io_response(Vfs::Vfs_handle::Context *) override
|
||||||
{
|
{
|
||||||
|
/* some contexts may have been deblocked from select() */
|
||||||
|
if (libc_select_notify)
|
||||||
|
libc_select_notify();
|
||||||
|
|
||||||
|
/* resume all as any context may have been deblocked from blocking I/O */
|
||||||
Libc::resume_all();
|
Libc::resume_all();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -781,7 +781,8 @@ int Libc::Vfs_plugin::select(int nfds,
|
|||||||
FD_SET(fd, readfds);
|
FD_SET(fd, readfds);
|
||||||
++nready;
|
++nready;
|
||||||
} else {
|
} else {
|
||||||
// handle->fs().notify_read_ready(handle);
|
while (!handle->fs().notify_read_ready(handle))
|
||||||
|
Libc::suspend();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -424,9 +424,9 @@ class Vfs::Dir_file_system : public File_system
|
|||||||
}
|
}
|
||||||
|
|
||||||
Open_result open(char const *path,
|
Open_result open(char const *path,
|
||||||
unsigned mode,
|
unsigned mode,
|
||||||
Vfs_handle **out_handle,
|
Vfs_handle **out_handle,
|
||||||
Allocator &alloc) override
|
Allocator &alloc) override
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* If 'path' is a directory, we create a 'Vfs_handle'
|
* If 'path' is a directory, we create a 'Vfs_handle'
|
||||||
@ -631,6 +631,14 @@ class Vfs::Dir_file_system : public File_system
|
|||||||
|
|
||||||
return handle->fs().read_ready(handle);
|
return handle->fs().read_ready(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool notify_read_ready(Vfs_handle *handle) override
|
||||||
|
{
|
||||||
|
if (&handle->fs() == this)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return handle->fs().notify_read_ready(handle);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* _INCLUDE__VFS__DIR_FILE_SYSTEM_H_ */
|
#endif /* _INCLUDE__VFS__DIR_FILE_SYSTEM_H_ */
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
#ifndef _INCLUDE__VFS__FILE_IO_SERVICE_H_
|
#ifndef _INCLUDE__VFS__FILE_IO_SERVICE_H_
|
||||||
#define _INCLUDE__VFS__FILE_IO_SERVICE_H_
|
#define _INCLUDE__VFS__FILE_IO_SERVICE_H_
|
||||||
|
|
||||||
|
#include <vfs/vfs_handle.h>
|
||||||
|
|
||||||
namespace Vfs {
|
namespace Vfs {
|
||||||
class Vfs_handle;
|
class Vfs_handle;
|
||||||
struct Io_response_handler;
|
struct Io_response_handler;
|
||||||
@ -25,7 +27,7 @@ namespace Vfs {
|
|||||||
|
|
||||||
struct Vfs::Io_response_handler
|
struct Vfs::Io_response_handler
|
||||||
{
|
{
|
||||||
virtual void handle_io_response() = 0;
|
virtual void handle_io_response(Vfs::Vfs_handle::Context *context) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -81,6 +83,16 @@ struct Vfs::File_io_service
|
|||||||
*/
|
*/
|
||||||
virtual bool read_ready(Vfs_handle *) = 0;
|
virtual bool read_ready(Vfs_handle *) = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Explicitly indicate interest in read-ready for a handle
|
||||||
|
*
|
||||||
|
* For example, the file-system-session plugin can then send READ_READY
|
||||||
|
* packets to the server.
|
||||||
|
*
|
||||||
|
* \return false if notification setup failed
|
||||||
|
*/
|
||||||
|
virtual bool notify_read_ready(Vfs_handle *) { return true; }
|
||||||
|
|
||||||
|
|
||||||
/***************
|
/***************
|
||||||
** Ftruncate **
|
** Ftruncate **
|
||||||
|
@ -14,10 +14,12 @@
|
|||||||
#ifndef _INCLUDE__VFS__VFS_HANDLE_H_
|
#ifndef _INCLUDE__VFS__VFS_HANDLE_H_
|
||||||
#define _INCLUDE__VFS__VFS_HANDLE_H_
|
#define _INCLUDE__VFS__VFS_HANDLE_H_
|
||||||
|
|
||||||
#include <vfs/file_io_service.h>
|
|
||||||
#include <vfs/directory_service.h>
|
#include <vfs/directory_service.h>
|
||||||
|
|
||||||
namespace Vfs { class Vfs_handle; }
|
namespace Vfs{
|
||||||
|
class Vfs_handle;
|
||||||
|
class File_io_service;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class Vfs::Vfs_handle
|
class Vfs::Vfs_handle
|
||||||
@ -32,6 +34,13 @@ class Vfs::Vfs_handle
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opaque handle context
|
||||||
|
*/
|
||||||
|
struct Context { };
|
||||||
|
|
||||||
|
Context *context = nullptr;
|
||||||
|
|
||||||
struct Guard
|
struct Guard
|
||||||
{
|
{
|
||||||
Vfs_handle *handle;
|
Vfs_handle *handle;
|
||||||
|
@ -151,7 +151,7 @@ struct Cli_monitor::Main
|
|||||||
|
|
||||||
struct Io_response_handler : Vfs::Io_response_handler
|
struct Io_response_handler : Vfs::Io_response_handler
|
||||||
{
|
{
|
||||||
void handle_io_response() { }
|
void handle_io_response(Vfs::Vfs_handle::Context *) override { }
|
||||||
} io_response_handler;
|
} io_response_handler;
|
||||||
|
|
||||||
/* initialize virtual file system */
|
/* initialize virtual file system */
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
/*
|
/*
|
||||||
* \brief Adapter from Genode 'File_system' session to VFS
|
* \brief Adapter from Genode 'File_system' session to VFS
|
||||||
* \author Norman Feske
|
* \author Norman Feske
|
||||||
|
* \author Emery Hemingway
|
||||||
|
* \author Christian Helmuth
|
||||||
* \date 2011-02-17
|
* \date 2011-02-17
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2012-2016 Genode Labs GmbH
|
* Copyright (C) 2012-2017 Genode Labs GmbH
|
||||||
*
|
*
|
||||||
* This file is part of the Genode OS framework, which is distributed
|
* This file is part of the Genode OS framework, which is distributed
|
||||||
* under the terms of the GNU General Public License version 2.
|
* under the terms of the GNU General Public License version 2.
|
||||||
@ -16,8 +18,10 @@
|
|||||||
|
|
||||||
/* Genode includes */
|
/* Genode includes */
|
||||||
#include <base/allocator_avl.h>
|
#include <base/allocator_avl.h>
|
||||||
|
#include <base/id_space.h>
|
||||||
#include <file_system_session/connection.h>
|
#include <file_system_session/connection.h>
|
||||||
|
|
||||||
|
|
||||||
namespace Vfs { class Fs_file_system; }
|
namespace Vfs { class Fs_file_system; }
|
||||||
|
|
||||||
|
|
||||||
@ -37,6 +41,7 @@ class Vfs::Fs_file_system : public File_system
|
|||||||
|
|
||||||
Genode::Env &_env;
|
Genode::Env &_env;
|
||||||
Genode::Allocator_avl _fs_packet_alloc;
|
Genode::Allocator_avl _fs_packet_alloc;
|
||||||
|
Io_response_handler &_io_handler;
|
||||||
|
|
||||||
typedef Genode::String<64> Label_string;
|
typedef Genode::String<64> Label_string;
|
||||||
Label_string _label;
|
Label_string _label;
|
||||||
@ -46,126 +51,244 @@ class Vfs::Fs_file_system : public File_system
|
|||||||
|
|
||||||
::File_system::Connection _fs;
|
::File_system::Connection _fs;
|
||||||
|
|
||||||
class Fs_vfs_handle : public Vfs_handle
|
struct Fs_vfs_handle;
|
||||||
|
|
||||||
|
struct Handle_space : Genode::Id_space<Fs_vfs_handle>
|
||||||
{
|
{
|
||||||
private:
|
struct Id : Genode::Id_space<Fs_vfs_handle>::Id
|
||||||
|
{
|
||||||
|
Id(unsigned long v) { value = v; }
|
||||||
|
Id(::File_system::Node_handle h) { value = h.value; }
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
::File_system::File_handle const _handle;
|
Handle_space _handle_space;
|
||||||
|
|
||||||
public:
|
struct Handle_state
|
||||||
|
{
|
||||||
|
enum class Read_ready_state { IDLE, PENDING, READY };
|
||||||
|
Read_ready_state read_ready_state = Read_ready_state::IDLE;
|
||||||
|
|
||||||
Fs_vfs_handle(File_system &fs, Allocator &alloc,
|
enum class Queued_state { IDLE, QUEUED, ACK };
|
||||||
int status_flags, ::File_system::File_handle handle)
|
Queued_state queued_read_state = Queued_state::IDLE;
|
||||||
: Vfs_handle(fs, fs, alloc, status_flags), _handle(handle)
|
Queued_state queued_write_state = Queued_state::IDLE;
|
||||||
{ }
|
|
||||||
|
|
||||||
::File_system::File_handle file_handle() const { return _handle; }
|
::File_system::Packet_descriptor queued_read_packet;
|
||||||
|
::File_system::Packet_descriptor queued_write_packet;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Fs_vfs_handle : Vfs_handle, Handle_space::Element, Handle_state
|
||||||
|
{
|
||||||
|
Handle_space::Id const id;
|
||||||
|
|
||||||
|
Fs_vfs_handle(File_system &fs, Allocator &alloc, int status_flags,
|
||||||
|
Handle_space &space, Handle_space::Id id)
|
||||||
|
:
|
||||||
|
Vfs_handle(fs, fs, alloc, status_flags),
|
||||||
|
Handle_space::Element(*this, space, id),
|
||||||
|
id(id)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
::File_system::File_handle file_handle() const { return id.value; }
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper for managing the lifetime of temporary open node handles
|
* Helper for managing the lifetime of temporary open node handles
|
||||||
*/
|
*/
|
||||||
struct Fs_handle_guard
|
struct Fs_handle_guard : Fs_vfs_handle
|
||||||
{
|
{
|
||||||
::File_system::Session &_fs;
|
::File_system::Session &_fs_session;
|
||||||
::File_system::Node_handle _handle;
|
::File_system::Node_handle _fs_handle;
|
||||||
|
|
||||||
Fs_handle_guard(::File_system::Session &fs,
|
Fs_handle_guard(File_system &fs,
|
||||||
::File_system::Node_handle handle)
|
::File_system::Session &fs_session,
|
||||||
: _fs(fs), _handle(handle) { }
|
::File_system::Node_handle fs_handle,
|
||||||
|
Handle_space &space)
|
||||||
|
:
|
||||||
|
Fs_vfs_handle(fs, *(Allocator*)nullptr, 0, space, Handle_space::Id(fs_handle)),
|
||||||
|
_fs_session(fs_session), _fs_handle(fs_handle)
|
||||||
|
{ }
|
||||||
|
|
||||||
~Fs_handle_guard() { _fs.close(_handle); }
|
~Fs_handle_guard() { _fs_session.close(_fs_handle); }
|
||||||
};
|
};
|
||||||
|
|
||||||
file_size _read(::File_system::Node_handle node_handle, void *buf,
|
struct Post_signal_hook : Genode::Entrypoint::Post_signal_hook
|
||||||
|
{
|
||||||
|
Genode::Entrypoint &_ep;
|
||||||
|
Io_response_handler &_io_handler;
|
||||||
|
Vfs_handle::Context *_context = nullptr;
|
||||||
|
|
||||||
|
Post_signal_hook(Genode::Entrypoint &ep,
|
||||||
|
Io_response_handler &io_handler)
|
||||||
|
: _ep(ep), _io_handler(io_handler) { }
|
||||||
|
|
||||||
|
void arm(Vfs_handle::Context *context)
|
||||||
|
{
|
||||||
|
_context = context;
|
||||||
|
_ep.schedule_post_signal_hook(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void function() override
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* XXX The current implementation executes the post signal hook
|
||||||
|
* for the last armed context only. When changing this,
|
||||||
|
* beware that the called handle_io_response() may change
|
||||||
|
* this object in a signal handler.
|
||||||
|
*/
|
||||||
|
|
||||||
|
_io_handler.handle_io_response(_context);
|
||||||
|
_context = nullptr;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Post_signal_hook _post_signal_hook { _env.ep(), _io_handler };
|
||||||
|
|
||||||
|
file_size _read(Fs_vfs_handle &handle, void *buf,
|
||||||
file_size const count, file_size const seek_offset)
|
file_size const count, file_size const seek_offset)
|
||||||
{
|
{
|
||||||
::File_system::Session::Tx::Source &source = *_fs.tx();
|
::File_system::Session::Tx::Source &source = *_fs.tx();
|
||||||
|
using ::File_system::Packet_descriptor;
|
||||||
|
|
||||||
file_size const max_packet_size = source.bulk_buffer_size() / 2;
|
file_size const max_packet_size = source.bulk_buffer_size() / 2;
|
||||||
file_size const clipped_count = min(max_packet_size, count);
|
file_size const clipped_count = min(max_packet_size, count);
|
||||||
|
|
||||||
::File_system::Packet_descriptor const
|
/* XXX check if alloc_packet() and submit_packet() will succeed! */
|
||||||
packet_in(source.alloc_packet(clipped_count),
|
|
||||||
node_handle,
|
Packet_descriptor const packet_in(source.alloc_packet(clipped_count),
|
||||||
::File_system::Packet_descriptor::READ,
|
handle.file_handle(),
|
||||||
clipped_count,
|
Packet_descriptor::READ,
|
||||||
seek_offset);
|
clipped_count,
|
||||||
|
seek_offset);
|
||||||
|
|
||||||
/* pass packet to server side */
|
/* pass packet to server side */
|
||||||
source.submit_packet(packet_in);
|
source.submit_packet(packet_in);
|
||||||
|
|
||||||
|
/* wait until packet was acknowledged */
|
||||||
|
handle.queued_read_state = Handle_state::Queued_state::QUEUED;
|
||||||
|
do {
|
||||||
|
_env.ep().wait_and_dispatch_one_signal();
|
||||||
|
} while (handle.queued_read_state != Handle_state::Queued_state::ACK);
|
||||||
|
|
||||||
/* obtain result packet descriptor with updated status info */
|
/* obtain result packet descriptor with updated status info */
|
||||||
::File_system::Packet_descriptor const
|
Packet_descriptor const packet_out = handle.queued_read_packet;
|
||||||
packet_out = source.get_acked_packet();
|
|
||||||
|
handle.queued_read_state = Handle_state::Queued_state::IDLE;
|
||||||
|
handle.queued_read_packet = Packet_descriptor();
|
||||||
|
|
||||||
|
if (!packet_out.succeeded()) {
|
||||||
|
/* could be EOF or a real error */
|
||||||
|
::File_system::Status status = _fs.status(handle.file_handle());
|
||||||
|
if (seek_offset < status.size)
|
||||||
|
Genode::warning("unexpected failure on file-system read");
|
||||||
|
}
|
||||||
|
|
||||||
file_size const read_num_bytes = min(packet_out.length(), count);
|
file_size const read_num_bytes = min(packet_out.length(), count);
|
||||||
|
|
||||||
memcpy(buf, source.packet_content(packet_out), read_num_bytes);
|
memcpy(buf, source.packet_content(packet_out), read_num_bytes);
|
||||||
|
|
||||||
/*
|
|
||||||
* XXX check if acked packet belongs to request,
|
|
||||||
* needed for thread safety
|
|
||||||
*/
|
|
||||||
|
|
||||||
source.release_packet(packet_out);
|
source.release_packet(packet_out);
|
||||||
|
|
||||||
return read_num_bytes;
|
return read_num_bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
file_size _write(::File_system::Node_handle node_handle,
|
file_size _write(Fs_vfs_handle &handle,
|
||||||
const char *buf, file_size count, file_size seek_offset)
|
const char *buf, file_size count, file_size seek_offset)
|
||||||
{
|
{
|
||||||
::File_system::Session::Tx::Source &source = *_fs.tx();
|
::File_system::Session::Tx::Source &source = *_fs.tx();
|
||||||
|
using ::File_system::Packet_descriptor;
|
||||||
|
|
||||||
file_size const max_packet_size = source.bulk_buffer_size() / 2;
|
file_size const max_packet_size = source.bulk_buffer_size() / 2;
|
||||||
count = min(max_packet_size, count);
|
count = min(max_packet_size, count);
|
||||||
|
|
||||||
::File_system::Packet_descriptor
|
/* XXX check if alloc_packet() and submit_packet() will succeed! */
|
||||||
packet(source.alloc_packet(count),
|
|
||||||
node_handle,
|
|
||||||
::File_system::Packet_descriptor::WRITE,
|
|
||||||
count,
|
|
||||||
seek_offset);
|
|
||||||
|
|
||||||
memcpy(source.packet_content(packet), buf, count);
|
Packet_descriptor packet_in(source.alloc_packet(count),
|
||||||
|
handle.file_handle(),
|
||||||
|
Packet_descriptor::WRITE,
|
||||||
|
count,
|
||||||
|
seek_offset);
|
||||||
|
|
||||||
|
memcpy(source.packet_content(packet_in), buf, count);
|
||||||
|
|
||||||
/* pass packet to server side */
|
/* pass packet to server side */
|
||||||
source.submit_packet(packet);
|
source.submit_packet(packet_in);
|
||||||
|
|
||||||
|
/* wait until packet was acknowledged */
|
||||||
|
handle.queued_write_state = Handle_state::Queued_state::QUEUED;
|
||||||
|
do {
|
||||||
|
_env.ep().wait_and_dispatch_one_signal();
|
||||||
|
} while (handle.queued_write_state != Handle_state::Queued_state::ACK);
|
||||||
|
|
||||||
/* obtain result packet descriptor with updated status info */
|
/* obtain result packet descriptor with updated status info */
|
||||||
::File_system::Packet_descriptor const
|
Packet_descriptor const packet_out = handle.queued_write_packet;
|
||||||
packet_out = source.get_acked_packet();
|
|
||||||
|
|
||||||
/*
|
handle.queued_write_state = Handle_state::Queued_state::IDLE;
|
||||||
* XXX check if acked packet belongs to request,
|
handle.queued_write_packet = Packet_descriptor();
|
||||||
* needed for thread safety
|
|
||||||
*/
|
|
||||||
|
|
||||||
file_size const write_num_bytes = min(packet_out.length(), count);
|
file_size const write_num_bytes = min(packet_out.length(), count);
|
||||||
|
|
||||||
source.release_packet(packet);
|
source.release_packet(packet_out);
|
||||||
|
|
||||||
return write_num_bytes;
|
return write_num_bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _handle_ack()
|
||||||
|
{
|
||||||
|
::File_system::Session::Tx::Source &source = *_fs.tx();
|
||||||
|
using ::File_system::Packet_descriptor;
|
||||||
|
|
||||||
|
while (source.ack_avail()) {
|
||||||
|
|
||||||
|
Packet_descriptor const packet = source.get_acked_packet();
|
||||||
|
|
||||||
|
Handle_space::Id const id(packet.handle());
|
||||||
|
|
||||||
|
_handle_space.apply<Fs_vfs_handle>(id, [&] (Fs_vfs_handle &handle)
|
||||||
|
{
|
||||||
|
switch (packet.operation()) {
|
||||||
|
case Packet_descriptor::READ_READY:
|
||||||
|
handle.read_ready_state = Handle_state::Read_ready_state::READY;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Packet_descriptor::READ:
|
||||||
|
handle.queued_read_packet = packet;
|
||||||
|
handle.queued_read_state = Handle_state::Queued_state::ACK;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Packet_descriptor::WRITE:
|
||||||
|
handle.queued_write_packet = packet;
|
||||||
|
handle.queued_write_state = Handle_state::Queued_state::ACK;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
_post_signal_hook.arm(handle.context);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Genode::Signal_handler<Fs_file_system> _ack_handler {
|
||||||
|
_env.ep(), *this, &Fs_file_system::_handle_ack };
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Fs_file_system(Genode::Env &env,
|
Fs_file_system(Genode::Env &env,
|
||||||
Genode::Allocator &alloc,
|
Genode::Allocator &alloc,
|
||||||
Genode::Xml_node config,
|
Genode::Xml_node config,
|
||||||
Io_response_handler &)
|
Io_response_handler &io_handler)
|
||||||
:
|
:
|
||||||
_env(env),
|
_env(env),
|
||||||
_fs_packet_alloc(&alloc),
|
_fs_packet_alloc(&alloc),
|
||||||
|
_io_handler(io_handler),
|
||||||
_label(config.attribute_value("label", Label_string())),
|
_label(config.attribute_value("label", Label_string())),
|
||||||
_root( config.attribute_value("root", Root_string())),
|
_root( config.attribute_value("root", Root_string())),
|
||||||
_fs(env, _fs_packet_alloc,
|
_fs(env, _fs_packet_alloc,
|
||||||
_label.string(), _root.string(),
|
_label.string(), _root.string(),
|
||||||
config.attribute_value("writeable", true),
|
config.attribute_value("writeable", true),
|
||||||
::File_system::DEFAULT_TX_BUF_SIZE)
|
::File_system::DEFAULT_TX_BUF_SIZE)
|
||||||
{ }
|
{
|
||||||
|
_fs.sigh_ack_avail(_ack_handler);
|
||||||
|
}
|
||||||
|
|
||||||
/*********************************
|
/*********************************
|
||||||
** Directory-service interface **
|
** Directory-service interface **
|
||||||
@ -187,12 +310,12 @@ class Vfs::Fs_file_system : public File_system
|
|||||||
try {
|
try {
|
||||||
::File_system::Dir_handle dir = _fs.dir(dir_path.base(),
|
::File_system::Dir_handle dir = _fs.dir(dir_path.base(),
|
||||||
false);
|
false);
|
||||||
Fs_handle_guard dir_guard(_fs, dir);
|
Fs_handle_guard dir_guard(*this, _fs, dir, _handle_space);
|
||||||
|
|
||||||
::File_system::File_handle file =
|
::File_system::File_handle file =
|
||||||
_fs.file(dir, file_name.base() + 1,
|
_fs.file(dir, file_name.base() + 1,
|
||||||
::File_system::READ_ONLY, false);
|
::File_system::READ_ONLY, false);
|
||||||
Fs_handle_guard file_guard(_fs, file);
|
Fs_handle_guard file_guard(*this, _fs, file, _handle_space);
|
||||||
|
|
||||||
::File_system::Status status = _fs.status(file);
|
::File_system::Status status = _fs.status(file);
|
||||||
|
|
||||||
@ -210,25 +333,7 @@ class Vfs::Fs_file_system : public File_system
|
|||||||
file_size const count = min(max_packet_size, status.size -
|
file_size const count = min(max_packet_size, status.size -
|
||||||
seek_offset);
|
seek_offset);
|
||||||
|
|
||||||
::File_system::Packet_descriptor
|
_read(file_guard, local_addr + seek_offset, count, seek_offset);
|
||||||
packet(source.alloc_packet(count),
|
|
||||||
file,
|
|
||||||
::File_system::Packet_descriptor::READ,
|
|
||||||
count,
|
|
||||||
seek_offset);
|
|
||||||
|
|
||||||
/* pass packet to server side */
|
|
||||||
source.submit_packet(packet);
|
|
||||||
source.get_acked_packet();
|
|
||||||
|
|
||||||
memcpy(local_addr + seek_offset, source.packet_content(packet), count);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* XXX check if acked packet belongs to request,
|
|
||||||
* needed for thread safety
|
|
||||||
*/
|
|
||||||
|
|
||||||
source.release_packet(packet);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_env.rm().detach(local_addr);
|
_env.rm().detach(local_addr);
|
||||||
@ -253,7 +358,7 @@ class Vfs::Fs_file_system : public File_system
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
::File_system::Node_handle node = _fs.node(path);
|
::File_system::Node_handle node = _fs.node(path);
|
||||||
Fs_handle_guard node_guard(_fs, node);
|
Fs_handle_guard node_guard(*this, _fs, node, _handle_space);
|
||||||
status = _fs.status(node);
|
status = _fs.status(node);
|
||||||
}
|
}
|
||||||
catch (::File_system::Lookup_failed) { return STAT_ERR_NO_ENTRY; }
|
catch (::File_system::Lookup_failed) { return STAT_ERR_NO_ENTRY; }
|
||||||
@ -281,7 +386,7 @@ class Vfs::Fs_file_system : public File_system
|
|||||||
{
|
{
|
||||||
Lock::Guard guard(_lock);
|
Lock::Guard guard(_lock);
|
||||||
|
|
||||||
::File_system::Session::Tx::Source &source = *_fs.tx();
|
using ::File_system::Directory_entry;
|
||||||
|
|
||||||
if (strcmp(path, "") == 0)
|
if (strcmp(path, "") == 0)
|
||||||
path = "/";
|
path = "/";
|
||||||
@ -291,31 +396,13 @@ class Vfs::Fs_file_system : public File_system
|
|||||||
catch (::File_system::Lookup_failed) { return DIRENT_ERR_INVALID_PATH; }
|
catch (::File_system::Lookup_failed) { return DIRENT_ERR_INVALID_PATH; }
|
||||||
catch (::File_system::Name_too_long) { return DIRENT_ERR_INVALID_PATH; }
|
catch (::File_system::Name_too_long) { return DIRENT_ERR_INVALID_PATH; }
|
||||||
catch (...) { return DIRENT_ERR_NO_PERM; }
|
catch (...) { return DIRENT_ERR_NO_PERM; }
|
||||||
Fs_handle_guard dir_guard(_fs, dir_handle);
|
|
||||||
|
|
||||||
enum { DIRENT_SIZE = sizeof(::File_system::Directory_entry) };
|
Fs_handle_guard dir_guard(*this, _fs, dir_handle, _handle_space);
|
||||||
|
Directory_entry entry;
|
||||||
|
|
||||||
::File_system::Packet_descriptor
|
enum { DIRENT_SIZE = sizeof(Directory_entry) };
|
||||||
packet(source.alloc_packet(DIRENT_SIZE),
|
|
||||||
dir_handle,
|
|
||||||
::File_system::Packet_descriptor::READ,
|
|
||||||
DIRENT_SIZE,
|
|
||||||
index*DIRENT_SIZE);
|
|
||||||
|
|
||||||
/* pass packet to server side */
|
_read(dir_guard, &entry, DIRENT_SIZE, index*DIRENT_SIZE);
|
||||||
source.submit_packet(packet);
|
|
||||||
source.get_acked_packet();
|
|
||||||
|
|
||||||
/*
|
|
||||||
* XXX check if acked packet belongs to request,
|
|
||||||
* needed for thread safety
|
|
||||||
*/
|
|
||||||
|
|
||||||
typedef ::File_system::Directory_entry Directory_entry;
|
|
||||||
|
|
||||||
/* copy-out payload into destination buffer */
|
|
||||||
Directory_entry const *entry =
|
|
||||||
(Directory_entry *)source.packet_content(packet);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The default value has no meaning because the switch below
|
* The default value has no meaning because the switch below
|
||||||
@ -324,17 +411,16 @@ class Vfs::Fs_file_system : public File_system
|
|||||||
*/
|
*/
|
||||||
Dirent_type type = DIRENT_TYPE_END;
|
Dirent_type type = DIRENT_TYPE_END;
|
||||||
|
|
||||||
switch (entry->type) {
|
/* copy-out payload into destination buffer */
|
||||||
|
switch (entry.type) {
|
||||||
case Directory_entry::TYPE_DIRECTORY: type = DIRENT_TYPE_DIRECTORY; break;
|
case Directory_entry::TYPE_DIRECTORY: type = DIRENT_TYPE_DIRECTORY; break;
|
||||||
case Directory_entry::TYPE_FILE: type = DIRENT_TYPE_FILE; break;
|
case Directory_entry::TYPE_FILE: type = DIRENT_TYPE_FILE; break;
|
||||||
case Directory_entry::TYPE_SYMLINK: type = DIRENT_TYPE_SYMLINK; break;
|
case Directory_entry::TYPE_SYMLINK: type = DIRENT_TYPE_SYMLINK; break;
|
||||||
}
|
}
|
||||||
|
|
||||||
out.fileno = entry->inode;
|
out.fileno = entry.inode;
|
||||||
out.type = type;
|
out.type = type;
|
||||||
strncpy(out.name, entry->name, sizeof(out.name));
|
strncpy(out.name, entry.name, sizeof(out.name));
|
||||||
|
|
||||||
source.release_packet(packet);
|
|
||||||
|
|
||||||
return DIRENT_OK;
|
return DIRENT_OK;
|
||||||
}
|
}
|
||||||
@ -349,7 +435,7 @@ class Vfs::Fs_file_system : public File_system
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
::File_system::Dir_handle dir = _fs.dir(dir_path.base(), false);
|
::File_system::Dir_handle dir = _fs.dir(dir_path.base(), false);
|
||||||
Fs_handle_guard dir_guard(_fs, dir);
|
Fs_handle_guard dir_guard(*this, _fs, dir, _handle_space);
|
||||||
|
|
||||||
_fs.unlink(dir, file_name.base() + 1);
|
_fs.unlink(dir, file_name.base() + 1);
|
||||||
}
|
}
|
||||||
@ -376,13 +462,13 @@ class Vfs::Fs_file_system : public File_system
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
::File_system::Dir_handle dir_handle = _fs.dir(abs_path.base(), false);
|
::File_system::Dir_handle dir_handle = _fs.dir(abs_path.base(), false);
|
||||||
Fs_handle_guard from_dir_guard(_fs, dir_handle);
|
Fs_handle_guard from_dir_guard(*this, _fs, dir_handle, _handle_space);
|
||||||
|
|
||||||
::File_system::Symlink_handle symlink_handle =
|
::File_system::Symlink_handle symlink_handle =
|
||||||
_fs.symlink(dir_handle, symlink_name.base() + 1, false);
|
_fs.symlink(dir_handle, symlink_name.base() + 1, false);
|
||||||
Fs_handle_guard symlink_guard(_fs, symlink_handle);
|
Fs_handle_guard symlink_guard(*this, _fs, symlink_handle, _handle_space);
|
||||||
|
|
||||||
out_len = _read(symlink_handle, buf, buf_size, 0);
|
out_len = _read(symlink_guard, buf, buf_size, 0);
|
||||||
|
|
||||||
return READLINK_OK;
|
return READLINK_OK;
|
||||||
}
|
}
|
||||||
@ -410,9 +496,9 @@ class Vfs::Fs_file_system : public File_system
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
::File_system::Dir_handle from_dir = _fs.dir(from_dir_path.base(), false);
|
::File_system::Dir_handle from_dir = _fs.dir(from_dir_path.base(), false);
|
||||||
Fs_handle_guard from_dir_guard(_fs, from_dir);
|
Fs_handle_guard from_dir_guard(*this, _fs, from_dir, _handle_space);
|
||||||
::File_system::Dir_handle to_dir = _fs.dir(to_dir_path.base(), false);
|
::File_system::Dir_handle to_dir = _fs.dir(to_dir_path.base(), false);
|
||||||
Fs_handle_guard to_dir_guard(_fs, to_dir);
|
Fs_handle_guard to_dir_guard(*this, _fs, to_dir, _handle_space);
|
||||||
|
|
||||||
_fs.move(from_dir, from_file_name.base() + 1,
|
_fs.move(from_dir, from_file_name.base() + 1,
|
||||||
to_dir, to_file_name.base() + 1);
|
to_dir, to_file_name.base() + 1);
|
||||||
@ -462,13 +548,13 @@ class Vfs::Fs_file_system : public File_system
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
::File_system::Dir_handle dir_handle = _fs.dir(abs_path.base(), false);
|
::File_system::Dir_handle dir_handle = _fs.dir(abs_path.base(), false);
|
||||||
Fs_handle_guard from_dir_guard(_fs, dir_handle);
|
Fs_handle_guard from_dir_guard(*this, _fs, dir_handle, _handle_space);
|
||||||
|
|
||||||
::File_system::Symlink_handle symlink_handle =
|
::File_system::Symlink_handle symlink_handle =
|
||||||
_fs.symlink(dir_handle, symlink_name.base() + 1, true);
|
_fs.symlink(dir_handle, symlink_name.base() + 1, true);
|
||||||
Fs_handle_guard symlink_guard(_fs, symlink_handle);
|
Fs_handle_guard symlink_guard(*this, _fs, symlink_handle, _handle_space);
|
||||||
|
|
||||||
_write(symlink_handle, from, strlen(from) + 1, 0);
|
_write(symlink_guard, from, strlen(from) + 1, 0);
|
||||||
}
|
}
|
||||||
catch (::File_system::Invalid_handle) { return SYMLINK_ERR_NO_ENTRY; }
|
catch (::File_system::Invalid_handle) { return SYMLINK_ERR_NO_ENTRY; }
|
||||||
catch (::File_system::Node_already_exists) { return SYMLINK_ERR_EXISTS; }
|
catch (::File_system::Node_already_exists) { return SYMLINK_ERR_EXISTS; }
|
||||||
@ -488,7 +574,7 @@ class Vfs::Fs_file_system : public File_system
|
|||||||
|
|
||||||
::File_system::Node_handle node;
|
::File_system::Node_handle node;
|
||||||
try { node = _fs.node(path); } catch (...) { return 0; }
|
try { node = _fs.node(path); } catch (...) { return 0; }
|
||||||
Fs_handle_guard node_guard(_fs, node);
|
Fs_handle_guard node_guard(*this, _fs, node, _handle_space);
|
||||||
|
|
||||||
::File_system::Status status = _fs.status(node);
|
::File_system::Status status = _fs.status(node);
|
||||||
|
|
||||||
@ -499,7 +585,7 @@ class Vfs::Fs_file_system : public File_system
|
|||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
::File_system::Node_handle node = _fs.node(path);
|
::File_system::Node_handle node = _fs.node(path);
|
||||||
Fs_handle_guard node_guard(_fs, node);
|
Fs_handle_guard node_guard(*this, _fs, node, _handle_space);
|
||||||
|
|
||||||
::File_system::Status status = _fs.status(node);
|
::File_system::Status status = _fs.status(node);
|
||||||
|
|
||||||
@ -543,12 +629,14 @@ class Vfs::Fs_file_system : public File_system
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
::File_system::Dir_handle dir = _fs.dir(dir_path.base(), false);
|
::File_system::Dir_handle dir = _fs.dir(dir_path.base(), false);
|
||||||
Fs_handle_guard dir_guard(_fs, dir);
|
Fs_handle_guard dir_guard(*this, _fs, dir, _handle_space);
|
||||||
|
|
||||||
::File_system::File_handle file = _fs.file(dir, file_name.base() + 1,
|
::File_system::File_handle file = _fs.file(dir, file_name.base() + 1,
|
||||||
mode, create);
|
mode, create);
|
||||||
|
|
||||||
*out_handle = new (alloc) Fs_vfs_handle(*this, alloc, vfs_mode, file);
|
Handle_space::Id id { file };
|
||||||
|
*out_handle = new (alloc)
|
||||||
|
Fs_vfs_handle(*this, alloc, vfs_mode, _handle_space, id);
|
||||||
}
|
}
|
||||||
catch (::File_system::Lookup_failed) { return OPEN_ERR_UNACCESSIBLE; }
|
catch (::File_system::Lookup_failed) { return OPEN_ERR_UNACCESSIBLE; }
|
||||||
catch (::File_system::Permission_denied) { return OPEN_ERR_NO_PERM; }
|
catch (::File_system::Permission_denied) { return OPEN_ERR_NO_PERM; }
|
||||||
@ -603,9 +691,9 @@ class Vfs::Fs_file_system : public File_system
|
|||||||
{
|
{
|
||||||
Lock::Guard guard(_lock);
|
Lock::Guard guard(_lock);
|
||||||
|
|
||||||
Fs_vfs_handle const *handle = static_cast<Fs_vfs_handle *>(vfs_handle);
|
Fs_vfs_handle &handle = static_cast<Fs_vfs_handle &>(*vfs_handle);
|
||||||
|
|
||||||
out_count = _write(handle->file_handle(), buf, buf_size, handle->seek());
|
out_count = _write(handle, buf, buf_size, handle.seek());
|
||||||
|
|
||||||
return WRITE_OK;
|
return WRITE_OK;
|
||||||
}
|
}
|
||||||
@ -615,22 +703,120 @@ class Vfs::Fs_file_system : public File_system
|
|||||||
{
|
{
|
||||||
Lock::Guard guard(_lock);
|
Lock::Guard guard(_lock);
|
||||||
|
|
||||||
Fs_vfs_handle const *handle = static_cast<Fs_vfs_handle *>(vfs_handle);
|
Fs_vfs_handle &handle = static_cast<Fs_vfs_handle &>(*vfs_handle);
|
||||||
|
|
||||||
::File_system::Status status = _fs.status(handle->file_handle());
|
/* reset the ready_ready state */
|
||||||
file_size const size_of_file = status.size;
|
handle.read_ready_state = Handle_state::Read_ready_state::IDLE;
|
||||||
|
|
||||||
file_size const file_bytes_left = size_of_file >= handle->seek()
|
out_count = _read(handle, dst, count, handle.seek());
|
||||||
? size_of_file - handle->seek() : 0;
|
|
||||||
|
|
||||||
count = min(count, file_bytes_left);
|
|
||||||
|
|
||||||
out_count = _read(handle->file_handle(), dst, count, handle->seek());
|
|
||||||
|
|
||||||
return READ_OK;
|
return READ_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool read_ready(Vfs_handle *) override { return true; }
|
bool queue_read(Vfs_handle *vfs_handle, char *dst, file_size count,
|
||||||
|
Read_result &out_result, file_size &out_count) override
|
||||||
|
{
|
||||||
|
Lock::Guard guard(_lock);
|
||||||
|
|
||||||
|
Fs_vfs_handle *handle = static_cast<Fs_vfs_handle *>(vfs_handle);
|
||||||
|
|
||||||
|
if (handle->queued_read_state != Handle_state::Queued_state::IDLE)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
::File_system::Session::Tx::Source &source = *_fs.tx();
|
||||||
|
|
||||||
|
/* if not ready to submit suggest retry */
|
||||||
|
if (!source.ready_to_submit()) return false;
|
||||||
|
|
||||||
|
file_size const max_packet_size = source.bulk_buffer_size() / 2;
|
||||||
|
file_size const clipped_count = min(max_packet_size, count);
|
||||||
|
|
||||||
|
::File_system::Packet_descriptor p;
|
||||||
|
try {
|
||||||
|
p = source.alloc_packet(clipped_count);
|
||||||
|
} catch (::File_system::Session::Tx::Source::Packet_alloc_failed) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
::File_system::Packet_descriptor const
|
||||||
|
packet(p, handle->file_handle(),
|
||||||
|
::File_system::Packet_descriptor::READ,
|
||||||
|
clipped_count, handle->seek());
|
||||||
|
|
||||||
|
/* pass packet to server side */
|
||||||
|
source.submit_packet(packet);
|
||||||
|
|
||||||
|
handle->read_ready_state = Handle_state::Read_ready_state::IDLE;
|
||||||
|
handle->queued_read_state = Handle_state::Queued_state::QUEUED;
|
||||||
|
|
||||||
|
out_result = READ_QUEUED;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Read_result complete_read(Vfs_handle *vfs_handle, char *dst, file_size count,
|
||||||
|
file_size &out_count) override
|
||||||
|
{
|
||||||
|
Lock::Guard guard(_lock);
|
||||||
|
|
||||||
|
Fs_vfs_handle *handle = static_cast<Fs_vfs_handle *>(vfs_handle);
|
||||||
|
|
||||||
|
if (handle->queued_read_state != Handle_state::Queued_state::ACK)
|
||||||
|
return READ_QUEUED;
|
||||||
|
|
||||||
|
/* obtain result packet descriptor with updated status info */
|
||||||
|
::File_system::Packet_descriptor const
|
||||||
|
packet = handle->queued_read_packet;
|
||||||
|
|
||||||
|
file_size const read_num_bytes = min(packet.length(), count);
|
||||||
|
|
||||||
|
::File_system::Session::Tx::Source &source = *_fs.tx();
|
||||||
|
|
||||||
|
memcpy(dst, source.packet_content(packet), read_num_bytes);
|
||||||
|
|
||||||
|
source.release_packet(packet);
|
||||||
|
handle->queued_read_state = Handle_state::Queued_state::IDLE;
|
||||||
|
handle->queued_read_packet = ::File_system::Packet_descriptor();
|
||||||
|
|
||||||
|
out_count = read_num_bytes;
|
||||||
|
|
||||||
|
return READ_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool read_ready(Vfs_handle *vfs_handle) override
|
||||||
|
{
|
||||||
|
Fs_vfs_handle *handle = static_cast<Fs_vfs_handle *>(vfs_handle);
|
||||||
|
|
||||||
|
return handle->read_ready_state == Handle_state::Read_ready_state::READY;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool notify_read_ready(Vfs_handle *vfs_handle) override
|
||||||
|
{
|
||||||
|
Fs_vfs_handle *handle = static_cast<Fs_vfs_handle *>(vfs_handle);
|
||||||
|
if (handle->read_ready_state != Handle_state::Read_ready_state::IDLE)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
::File_system::Session::Tx::Source &source = *_fs.tx();
|
||||||
|
|
||||||
|
/* if not ready to submit suggest retry */
|
||||||
|
if (!source.ready_to_submit()) return false;
|
||||||
|
|
||||||
|
using ::File_system::Packet_descriptor;
|
||||||
|
|
||||||
|
Packet_descriptor packet(Packet_descriptor(),
|
||||||
|
handle->file_handle(),
|
||||||
|
Packet_descriptor::READ_READY,
|
||||||
|
0, 0);
|
||||||
|
|
||||||
|
source.submit_packet(packet);
|
||||||
|
handle->read_ready_state = Handle_state::Read_ready_state::PENDING;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When the packet is acknowledged the application is notified via
|
||||||
|
* Io_response_handler::handle_io_response().
|
||||||
|
*/
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
Ftruncate_result ftruncate(Vfs_handle *vfs_handle, file_size len) override
|
Ftruncate_result ftruncate(Vfs_handle *vfs_handle, file_size len) override
|
||||||
{
|
{
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
#include <terminal_session/connection.h>
|
#include <terminal_session/connection.h>
|
||||||
#include <vfs/single_file_system.h>
|
#include <vfs/single_file_system.h>
|
||||||
#include <base/signal.h>
|
#include <base/signal.h>
|
||||||
|
#include <base/registry.h>
|
||||||
|
|
||||||
|
|
||||||
namespace Vfs { class Terminal_file_system; }
|
namespace Vfs { class Terminal_file_system; }
|
||||||
@ -36,10 +37,52 @@ class Vfs::Terminal_file_system : public Single_file_system
|
|||||||
|
|
||||||
Terminal::Connection _terminal { _env, _label.string() };
|
Terminal::Connection _terminal { _env, _label.string() };
|
||||||
|
|
||||||
|
typedef Genode::Registered<Vfs_handle> Registered_handle;
|
||||||
|
typedef Genode::Registry<Registered_handle> Handle_registry;
|
||||||
|
|
||||||
|
struct Post_signal_hook : Genode::Entrypoint::Post_signal_hook
|
||||||
|
{
|
||||||
|
Genode::Entrypoint &_ep;
|
||||||
|
Io_response_handler &_io_handler;
|
||||||
|
Vfs_handle::Context *_context = nullptr;
|
||||||
|
|
||||||
|
Post_signal_hook(Genode::Entrypoint &ep,
|
||||||
|
Io_response_handler &io_handler)
|
||||||
|
: _ep(ep), _io_handler(io_handler) { }
|
||||||
|
|
||||||
|
void arm(Vfs_handle::Context *context)
|
||||||
|
{
|
||||||
|
_context = context;
|
||||||
|
_ep.schedule_post_signal_hook(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void function() override
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* XXX The current implementation executes the post signal hook
|
||||||
|
* for the last armed context only. When changing this,
|
||||||
|
* beware that the called handle_io_response() may change
|
||||||
|
* this object in a signal handler.
|
||||||
|
*/
|
||||||
|
|
||||||
|
_io_handler.handle_io_response(_context);
|
||||||
|
_context = nullptr;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Post_signal_hook _post_signal_hook { _env.ep(), _io_handler };
|
||||||
|
|
||||||
|
Handle_registry _handle_registry;
|
||||||
|
|
||||||
Genode::Signal_handler<Terminal_file_system> _read_avail_handler {
|
Genode::Signal_handler<Terminal_file_system> _read_avail_handler {
|
||||||
_env.ep(), *this, &Terminal_file_system::_handle_read_avail };
|
_env.ep(), *this, &Terminal_file_system::_handle_read_avail };
|
||||||
|
|
||||||
void _handle_read_avail() { _io_handler.handle_io_response(); }
|
void _handle_read_avail()
|
||||||
|
{
|
||||||
|
_handle_registry.for_each([this] (Registered_handle &h) {
|
||||||
|
_post_signal_hook.arm(h.context);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
Read_result _read(Vfs_handle *vfs_handle, char *dst, file_size count,
|
Read_result _read(Vfs_handle *vfs_handle, char *dst, file_size count,
|
||||||
file_size &out_count)
|
file_size &out_count)
|
||||||
@ -70,6 +113,19 @@ class Vfs::Terminal_file_system : public Single_file_system
|
|||||||
static const char *name() { return "terminal"; }
|
static const char *name() { return "terminal"; }
|
||||||
char const *type() override { return "terminal"; }
|
char const *type() override { return "terminal"; }
|
||||||
|
|
||||||
|
Open_result open(char const *path, unsigned mode,
|
||||||
|
Vfs_handle **out_handle,
|
||||||
|
Allocator &alloc) override
|
||||||
|
{
|
||||||
|
if (!_single_file(path))
|
||||||
|
return OPEN_ERR_UNACCESSIBLE;
|
||||||
|
|
||||||
|
*out_handle = new (alloc)
|
||||||
|
Registered_handle(_handle_registry, *this, *this, alloc, 0);
|
||||||
|
|
||||||
|
return OPEN_OK;
|
||||||
|
}
|
||||||
|
|
||||||
/********************************
|
/********************************
|
||||||
** File I/O service interface **
|
** File I/O service interface **
|
||||||
********************************/
|
********************************/
|
||||||
|
@ -13,36 +13,37 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* Genode includes */
|
/* Genode includes */
|
||||||
#include <file_system_session/rpc_object.h>
|
|
||||||
#include <base/heap.h>
|
|
||||||
#include <ram_session/connection.h>
|
|
||||||
#include <root/component.h>
|
|
||||||
#include <vfs/dir_file_system.h>
|
|
||||||
#include <os/session_policy.h>
|
|
||||||
#include <vfs/file_system_factory.h>
|
|
||||||
#include <os/ram_session_guard.h>
|
|
||||||
#include <base/attached_rom_dataspace.h>
|
|
||||||
#include <base/sleep.h>
|
|
||||||
#include <base/component.h>
|
#include <base/component.h>
|
||||||
|
#include <base/registry.h>
|
||||||
|
#include <base/heap.h>
|
||||||
|
#include <base/attached_rom_dataspace.h>
|
||||||
|
#include <file_system_session/rpc_object.h>
|
||||||
|
#include <root/component.h>
|
||||||
|
#include <os/session_policy.h>
|
||||||
|
#include <os/ram_session_guard.h>
|
||||||
|
#include <vfs/dir_file_system.h>
|
||||||
|
#include <vfs/file_system_factory.h>
|
||||||
|
|
||||||
/* Local includes */
|
/* Local includes */
|
||||||
#include "assert.h"
|
#include "assert.h"
|
||||||
#include "node.h"
|
#include "node.h"
|
||||||
|
|
||||||
namespace Vfs_server {
|
|
||||||
|
|
||||||
|
namespace Vfs_server {
|
||||||
using namespace File_system;
|
using namespace File_system;
|
||||||
using namespace Vfs;
|
using namespace Vfs;
|
||||||
|
|
||||||
class Session_component;
|
class Session_component;
|
||||||
class Root;
|
class Root;
|
||||||
class Io_response_handler;
|
class Io_response_handler;
|
||||||
|
|
||||||
|
typedef Genode::Registered<Session_component> Registered_session;
|
||||||
|
typedef Genode::Registry<Registered_session> Session_registry;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class Vfs_server::Session_component :
|
class Vfs_server::Session_component : public File_system::Session_rpc_object,
|
||||||
public File_system::Session_rpc_object
|
public File_io_handler
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
|
||||||
@ -53,7 +54,7 @@ class Vfs_server::Session_component :
|
|||||||
|
|
||||||
Genode::Signal_handler<Session_component> _process_packet_handler;
|
Genode::Signal_handler<Session_component> _process_packet_handler;
|
||||||
|
|
||||||
Vfs::Dir_file_system &_vfs;
|
Vfs::Dir_file_system &_vfs;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The root node needs be allocated with the session struct
|
* The root node needs be allocated with the session struct
|
||||||
@ -61,8 +62,13 @@ class Vfs_server::Session_component :
|
|||||||
*/
|
*/
|
||||||
Genode::Constructible<Directory> _root;
|
Genode::Constructible<Directory> _root;
|
||||||
|
|
||||||
bool _writable;
|
bool _writable;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* XXX Currently, we have only one packet in backlog, which must finish
|
||||||
|
* processing before new packets can be processed.
|
||||||
|
*/
|
||||||
|
Packet_descriptor _backlog_packet;
|
||||||
|
|
||||||
/****************************
|
/****************************
|
||||||
** Handle to node mapping **
|
** Handle to node mapping **
|
||||||
@ -106,8 +112,14 @@ class Vfs_server::Session_component :
|
|||||||
** Packet-stream processing **
|
** Packet-stream processing **
|
||||||
******************************/
|
******************************/
|
||||||
|
|
||||||
|
struct Not_read_ready { };
|
||||||
|
struct Dont_ack { };
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Perform packet operation
|
* Perform packet operation
|
||||||
|
*
|
||||||
|
* \throw Not_read_ready
|
||||||
|
* \throw Dont_ack
|
||||||
*/
|
*/
|
||||||
void _process_packet_op(Packet_descriptor &packet)
|
void _process_packet_op(Packet_descriptor &packet)
|
||||||
{
|
{
|
||||||
@ -118,49 +130,100 @@ class Vfs_server::Session_component :
|
|||||||
/* assume failure by default */
|
/* assume failure by default */
|
||||||
packet.succeeded(false);
|
packet.succeeded(false);
|
||||||
|
|
||||||
if ((!(content && length)) || (packet.length() > packet.size())) {
|
if ((packet.length() > packet.size()))
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
/* resulting length */
|
/* resulting length */
|
||||||
size_t res_length = 0;
|
size_t res_length = 0;
|
||||||
|
|
||||||
switch (packet.operation()) {
|
switch (packet.operation()) {
|
||||||
|
|
||||||
case Packet_descriptor::READ: try {
|
case Packet_descriptor::READ:
|
||||||
_apply(packet.handle(), [&] (Node &node) {
|
try {
|
||||||
if (node.mode&READ_ONLY)
|
_apply(packet.handle(), [&] (Node &node) {
|
||||||
res_length = node.read(_vfs, (char *)content, length, seek);
|
if (!node.read_ready())
|
||||||
}); } catch (...) { }
|
throw Not_read_ready();
|
||||||
|
if (node.mode&READ_ONLY)
|
||||||
|
res_length = node.read(_vfs, (char *)content, length, seek);
|
||||||
|
});
|
||||||
|
} catch (Not_read_ready) { throw;
|
||||||
|
} catch (...) { }
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Packet_descriptor::WRITE: try {
|
case Packet_descriptor::WRITE:
|
||||||
_apply(packet.handle(), [&] (Node &node) {
|
try {
|
||||||
if (node.mode&WRITE_ONLY)
|
_apply(packet.handle(), [&] (Node &node) {
|
||||||
res_length = node.write(_vfs, (char const *)content, length, seek);
|
if (node.mode&WRITE_ONLY)
|
||||||
}); } catch (...) { }
|
res_length = node.write(_vfs, (char const *)content, length, seek);
|
||||||
|
});
|
||||||
|
} catch (...) { }
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Packet_descriptor::READ_READY:
|
case Packet_descriptor::READ_READY:
|
||||||
/* not supported */
|
try {
|
||||||
break;
|
_apply(static_cast<File_handle>(packet.handle().value), [] (File &node) {
|
||||||
|
node.notify_read_ready = true;
|
||||||
|
});
|
||||||
|
} catch (...) { }
|
||||||
|
|
||||||
|
throw Dont_ack();
|
||||||
}
|
}
|
||||||
|
|
||||||
packet.length(res_length);
|
packet.length(res_length);
|
||||||
packet.succeeded(!!res_length);
|
packet.succeeded(!!res_length);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _process_packet()
|
bool _try_process_packet_op(Packet_descriptor &packet)
|
||||||
{
|
{
|
||||||
Packet_descriptor packet = tx_sink()->get_packet();
|
try {
|
||||||
|
_process_packet_op(packet);
|
||||||
|
return true;
|
||||||
|
} catch (Not_read_ready) {
|
||||||
|
_backlog_packet = packet;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _process_backlog()
|
||||||
|
{
|
||||||
|
/* indicate success if there's no backlog */
|
||||||
|
if (!_backlog_packet.size())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
/* only start processing if acknowledgement is possible */
|
||||||
|
if (!tx_sink()->ready_to_ack())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!_try_process_packet_op(_backlog_packet))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The 'acknowledge_packet' function cannot block because we
|
||||||
|
* checked for 'ready_to_ack' in '_process_packets'.
|
||||||
|
*/
|
||||||
|
tx_sink()->acknowledge_packet(_backlog_packet);
|
||||||
|
|
||||||
|
/* invalidate backlog packet */
|
||||||
|
_backlog_packet = Packet_descriptor();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _process_packet()
|
||||||
|
{
|
||||||
|
Packet_descriptor packet = tx_sink()->get_packet();
|
||||||
|
|
||||||
|
if (!_try_process_packet_op(packet))
|
||||||
|
return false;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The 'acknowledge_packet' function cannot block because we
|
* The 'acknowledge_packet' function cannot block because we
|
||||||
* checked for 'ready_to_ack' in '_process_packets'.
|
* checked for 'ready_to_ack' in '_process_packets'.
|
||||||
*/
|
*/
|
||||||
_process_packet_op(packet);
|
|
||||||
tx_sink()->acknowledge_packet(packet);
|
tx_sink()->acknowledge_packet(packet);
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -169,6 +232,16 @@ class Vfs_server::Session_component :
|
|||||||
*/
|
*/
|
||||||
void _process_packets()
|
void _process_packets()
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
|
* XXX Process client backlog before looking at new requests. This
|
||||||
|
* limits the number of simultaneously addressed handles (which
|
||||||
|
* was also the case before adding the backlog in case of
|
||||||
|
* blocking operations).
|
||||||
|
*/
|
||||||
|
if (!_process_backlog())
|
||||||
|
/* backlog not cleared - block for next condition change */
|
||||||
|
return;
|
||||||
|
|
||||||
while (tx_sink()->packet_avail()) {
|
while (tx_sink()->packet_avail()) {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -186,7 +259,10 @@ class Vfs_server::Session_component :
|
|||||||
if (!tx_sink()->ready_to_ack())
|
if (!tx_sink()->ready_to_ack())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_process_packet();
|
try {
|
||||||
|
if (!_process_packet())
|
||||||
|
return;
|
||||||
|
} catch (Dont_ack) { }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -243,7 +319,6 @@ class Vfs_server::Session_component :
|
|||||||
_alloc(_ram, env.rm()),
|
_alloc(_ram, env.rm()),
|
||||||
_process_packet_handler(env.ep(), *this, &Session_component::_process_packets),
|
_process_packet_handler(env.ep(), *this, &Session_component::_process_packets),
|
||||||
_vfs(vfs),
|
_vfs(vfs),
|
||||||
_root(),
|
|
||||||
_writable(writable)
|
_writable(writable)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
@ -275,6 +350,19 @@ class Vfs_server::Session_component :
|
|||||||
_ram.upgrade(new_quota);
|
_ram.upgrade(new_quota);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* File_io_handler interface */
|
||||||
|
void handle_file_io(File &file) override
|
||||||
|
{
|
||||||
|
if (file.notify_read_ready && tx_sink()->ready_to_ack()) {
|
||||||
|
Packet_descriptor packet(Packet_descriptor(),
|
||||||
|
Node_handle(file.id().value),
|
||||||
|
Packet_descriptor::READ_READY,
|
||||||
|
0, 0);
|
||||||
|
tx_sink()->acknowledge_packet(packet);
|
||||||
|
file.notify_read_ready = false;
|
||||||
|
}
|
||||||
|
_process_packets();
|
||||||
|
}
|
||||||
|
|
||||||
/***************************
|
/***************************
|
||||||
** File_system interface **
|
** File_system interface **
|
||||||
@ -320,7 +408,7 @@ class Vfs_server::Session_component :
|
|||||||
_assert_valid_name(name_str);
|
_assert_valid_name(name_str);
|
||||||
|
|
||||||
new_handle = dir.file(
|
new_handle = dir.file(
|
||||||
_node_space, _vfs, _alloc, name_str, fs_mode, create).value;
|
_node_space, _vfs, _alloc, *this, name_str, fs_mode, create).value;
|
||||||
});
|
});
|
||||||
return new_handle;
|
return new_handle;
|
||||||
}
|
}
|
||||||
@ -425,9 +513,11 @@ class Vfs_server::Session_component :
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void truncate(File_handle file_handle, file_size_t size) override {
|
void truncate(File_handle file_handle, file_size_t size) override
|
||||||
|
{
|
||||||
_apply(file_handle, [&] (File &file) {
|
_apply(file_handle, [&] (File &file) {
|
||||||
file.truncate(size); }); }
|
file.truncate(size); });
|
||||||
|
}
|
||||||
|
|
||||||
void move(Dir_handle from_dir_handle, Name const &from_name,
|
void move(Dir_handle from_dir_handle, Name const &from_name,
|
||||||
Dir_handle to_dir_handle, Name const &to_name) override
|
Dir_handle to_dir_handle, Name const &to_name) override
|
||||||
@ -472,9 +562,15 @@ class Vfs_server::Session_component :
|
|||||||
|
|
||||||
struct Vfs_server::Io_response_handler : Vfs::Io_response_handler
|
struct Vfs_server::Io_response_handler : Vfs::Io_response_handler
|
||||||
{
|
{
|
||||||
void handle_io_response() override
|
Session_registry &_session_registry;
|
||||||
|
|
||||||
|
Io_response_handler(Session_registry &session_registry)
|
||||||
|
: _session_registry(session_registry) { }
|
||||||
|
|
||||||
|
void handle_io_response(Vfs::Vfs_handle::Context *context) override
|
||||||
{
|
{
|
||||||
Genode::log(__func__, " called");
|
if (Vfs_server::Node *node = static_cast<Vfs_server::Node *>(context))
|
||||||
|
node->handle_io_response();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -499,7 +595,9 @@ class Vfs_server::Root :
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Io_response_handler _io_response_handler;
|
Session_registry _session_registry;
|
||||||
|
|
||||||
|
Io_response_handler _io_response_handler { _session_registry };
|
||||||
|
|
||||||
Vfs::Dir_file_system _vfs {
|
Vfs::Dir_file_system _vfs {
|
||||||
_env, _heap, vfs_config(), _io_response_handler,
|
_env, _heap, vfs_config(), _io_response_handler,
|
||||||
@ -593,14 +691,10 @@ class Vfs_server::Root :
|
|||||||
throw Root::Unavailable();
|
throw Root::Unavailable();
|
||||||
}
|
}
|
||||||
|
|
||||||
Session_component *session = new(md_alloc())
|
Session_component *session = new (md_alloc())
|
||||||
Session_component(_env,
|
Registered_session(_session_registry, _env, label.string(),
|
||||||
label.string(),
|
ram_quota, tx_buf_size, _vfs,
|
||||||
ram_quota,
|
session_root.base(), writeable);
|
||||||
tx_buf_size,
|
|
||||||
_vfs,
|
|
||||||
session_root.base(),
|
|
||||||
writeable);
|
|
||||||
|
|
||||||
Genode::log("session opened for '", label, "' at '", session_root, "'");
|
Genode::log("session opened for '", label, "' at '", session_root, "'");
|
||||||
return session;
|
return session;
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
/*
|
/*
|
||||||
* \brief Internal nodes of VFS server
|
* \brief Internal nodes of VFS server
|
||||||
* \author Emery Hemingway
|
* \author Emery Hemingway
|
||||||
|
* \author Christian Helmuth
|
||||||
* \date 2016-03-29
|
* \date 2016-03-29
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2016 Genode Labs GmbH
|
* Copyright (C) 2016-2017 Genode Labs GmbH
|
||||||
*
|
*
|
||||||
* This file is part of the Genode OS framework, which is distributed
|
* This file is part of the Genode OS framework, which is distributed
|
||||||
* under the terms of the GNU General Public License version 2.
|
* under the terms of the GNU General Public License version 2.
|
||||||
@ -35,6 +36,11 @@ namespace Vfs_server {
|
|||||||
|
|
||||||
typedef Genode::Id_space<Node> Node_space;
|
typedef Genode::Id_space<Node> Node_space;
|
||||||
|
|
||||||
|
struct File_io_handler
|
||||||
|
{
|
||||||
|
virtual void handle_file_io(File &file) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
/* Vfs::MAX_PATH is shorter than File_system::MAX_PATH */
|
/* Vfs::MAX_PATH is shorter than File_system::MAX_PATH */
|
||||||
enum { MAX_PATH_LEN = Vfs::MAX_PATH_LEN };
|
enum { MAX_PATH_LEN = Vfs::MAX_PATH_LEN };
|
||||||
|
|
||||||
@ -70,7 +76,8 @@ namespace Vfs_server {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
struct Vfs_server::Node : File_system::Node_base, Node_space::Element
|
struct Vfs_server::Node : File_system::Node_base, Node_space::Element,
|
||||||
|
Vfs::Vfs_handle::Context
|
||||||
{
|
{
|
||||||
Path const _path;
|
Path const _path;
|
||||||
Mode const mode;
|
Mode const mode;
|
||||||
@ -87,7 +94,8 @@ struct Vfs_server::Node : File_system::Node_base, Node_space::Element
|
|||||||
|
|
||||||
virtual size_t read(Vfs::File_system&, char*, size_t, seek_off_t) { return 0; }
|
virtual size_t read(Vfs::File_system&, char*, size_t, seek_off_t) { return 0; }
|
||||||
virtual size_t write(Vfs::File_system&, char const*, size_t, seek_off_t) { return 0; }
|
virtual size_t write(Vfs::File_system&, char const*, size_t, seek_off_t) { return 0; }
|
||||||
|
virtual bool read_ready() { return false; }
|
||||||
|
virtual void handle_io_response() { }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Vfs_server::Symlink : Node
|
struct Vfs_server::Symlink : Node
|
||||||
@ -127,6 +135,8 @@ struct Vfs_server::Symlink : Node
|
|||||||
notify_listeners();
|
notify_listeners();
|
||||||
return target.length();
|
return target.length();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool read_ready() override { return true; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -134,24 +144,32 @@ class Vfs_server::File : public Node
|
|||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
File_io_handler &_file_io_handler;
|
||||||
|
|
||||||
Vfs::Vfs_handle *_handle;
|
Vfs::Vfs_handle *_handle;
|
||||||
char const *_leaf_path; /* offset pointer to Node::_path */
|
char const *_leaf_path; /* offset pointer to Node::_path */
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
File(Node_space &space,
|
bool notify_read_ready = false;
|
||||||
|
|
||||||
|
File(Node_space &space,
|
||||||
Vfs::File_system &vfs,
|
Vfs::File_system &vfs,
|
||||||
Genode::Allocator &alloc,
|
Genode::Allocator &alloc,
|
||||||
|
File_io_handler &file_io_handler,
|
||||||
char const *file_path,
|
char const *file_path,
|
||||||
Mode fs_mode,
|
Mode fs_mode,
|
||||||
bool create)
|
bool create)
|
||||||
: Node(space, file_path, fs_mode)
|
:
|
||||||
|
Node(space, file_path, fs_mode),
|
||||||
|
_file_io_handler(file_io_handler)
|
||||||
{
|
{
|
||||||
unsigned vfs_mode =
|
unsigned vfs_mode =
|
||||||
(fs_mode-1) | (create ? Vfs::Directory_service::OPEN_MODE_CREATE : 0);
|
(fs_mode-1) | (create ? Vfs::Directory_service::OPEN_MODE_CREATE : 0);
|
||||||
|
|
||||||
assert_open(vfs.open(file_path, vfs_mode, &_handle, alloc));
|
assert_open(vfs.open(file_path, vfs_mode, &_handle, alloc));
|
||||||
_leaf_path = vfs.leaf_path(path());
|
_leaf_path = vfs.leaf_path(path());
|
||||||
|
_handle->context = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
~File() { _handle->ds().close(_handle); }
|
~File() { _handle->ds().close(_handle); }
|
||||||
@ -167,7 +185,8 @@ class Vfs_server::File : public Node
|
|||||||
** Node interface **
|
** Node interface **
|
||||||
********************/
|
********************/
|
||||||
|
|
||||||
size_t read(Vfs::File_system&, char *dst, size_t len, seek_off_t seek_offset)
|
size_t read(Vfs::File_system&, char *dst, size_t len,
|
||||||
|
seek_off_t seek_offset) override
|
||||||
{
|
{
|
||||||
Vfs::file_size res = 0;
|
Vfs::file_size res = 0;
|
||||||
|
|
||||||
@ -185,7 +204,8 @@ class Vfs_server::File : public Node
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t write(Vfs::File_system&, char const *src, size_t len, seek_off_t seek_offset)
|
size_t write(Vfs::File_system&, char const *src, size_t len,
|
||||||
|
seek_off_t seek_offset) override
|
||||||
{
|
{
|
||||||
Vfs::file_size res = 0;
|
Vfs::file_size res = 0;
|
||||||
|
|
||||||
@ -204,6 +224,13 @@ class Vfs_server::File : public Node
|
|||||||
mark_as_updated();
|
mark_as_updated();
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool read_ready() override { return _handle->fs().read_ready(_handle); }
|
||||||
|
|
||||||
|
void handle_io_response() override
|
||||||
|
{
|
||||||
|
_file_io_handler.handle_file_io(*this);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -219,6 +246,7 @@ struct Vfs_server::Directory : Node
|
|||||||
Node_space::Id file(Node_space &space,
|
Node_space::Id file(Node_space &space,
|
||||||
Vfs::File_system &vfs,
|
Vfs::File_system &vfs,
|
||||||
Genode::Allocator &alloc,
|
Genode::Allocator &alloc,
|
||||||
|
File_io_handler &file_io_handler,
|
||||||
char const *file_path,
|
char const *file_path,
|
||||||
Mode mode,
|
Mode mode,
|
||||||
bool create)
|
bool create)
|
||||||
@ -227,8 +255,11 @@ struct Vfs_server::Directory : Node
|
|||||||
char const *path_str = subpath.base();
|
char const *path_str = subpath.base();
|
||||||
|
|
||||||
File *file;
|
File *file;
|
||||||
try { file = new (alloc) File(space, vfs, alloc, path_str, mode, create); }
|
try {
|
||||||
catch (Out_of_memory) { throw Out_of_metadata(); }
|
file = new (alloc)
|
||||||
|
File(space, vfs, alloc, file_io_handler, path_str, mode, create);
|
||||||
|
} catch (Out_of_memory) { throw Out_of_metadata(); }
|
||||||
|
|
||||||
if (create)
|
if (create)
|
||||||
mark_as_updated();
|
mark_as_updated();
|
||||||
return file->id();
|
return file->id();
|
||||||
@ -297,6 +328,8 @@ struct Vfs_server::Directory : Node
|
|||||||
}
|
}
|
||||||
return len - remains;
|
return len - remains;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool read_ready() override { return true; }
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* _VFS__NODE_H_ */
|
#endif /* _VFS__NODE_H_ */
|
||||||
|
@ -474,7 +474,10 @@ void Component::construct(Genode::Env &env)
|
|||||||
|
|
||||||
struct Io_response_handler : Vfs::Io_response_handler
|
struct Io_response_handler : Vfs::Io_response_handler
|
||||||
{
|
{
|
||||||
void handle_io_response() override { Genode::log(__func__, " called"); }
|
void handle_io_response(Vfs::Vfs_handle::Context *) override
|
||||||
|
{
|
||||||
|
Genode::log(__func__, " called");
|
||||||
|
}
|
||||||
} io_response_handler;
|
} io_response_handler;
|
||||||
|
|
||||||
Vfs::Dir_file_system vfs_root(env, heap, config_xml.sub_node("vfs"),
|
Vfs::Dir_file_system vfs_root(env, heap, config_xml.sub_node("vfs"),
|
||||||
|
@ -214,7 +214,7 @@ struct Noux::Main
|
|||||||
|
|
||||||
struct Io_response_handler : Vfs::Io_response_handler
|
struct Io_response_handler : Vfs::Io_response_handler
|
||||||
{
|
{
|
||||||
void handle_io_response() override { Genode::log(__func__, " called"); }
|
void handle_io_response(Vfs::Vfs_handle::Context *) override { }
|
||||||
} _io_response_handler;
|
} _io_response_handler;
|
||||||
|
|
||||||
Vfs::Dir_file_system _root_dir { _env, _heap, _config.xml().sub_node("fstab"),
|
Vfs::Dir_file_system _root_dir { _env, _heap, _config.xml().sub_node("fstab"),
|
||||||
|
Loading…
Reference in New Issue
Block a user