VFS: nonblocking interface

The VFS library can be used in single-threaded or multi-threaded
environments and depending on that, signals are handled by the same thread
which uses the VFS library or possibly by a different thread. If a VFS
plugin needs to block to wait for a signal, there is currently no way
which works reliably in both environments.

For this reason, this commit makes the interface of the VFS library
nonblocking, similar to the File_system session interface.

The most important changes are:

- Directories are created and opened with the 'opendir()' function and the
  directory entries are read with the recently introduced 'queue_read()'
  and 'complete_read()' functions.

- Symbolic links are created and opened with the 'openlink()' function and
  the link target is read with the 'queue_read()' and 'complete_read()'
  functions and written with the 'write()' function.

- The 'write()' function does not wait for signals anymore. This can have
  the effect that data written by a VFS library user has not been
  processed by a file system server yet when the library user asks for the
  size of the file or closes it (both done with RPC functions at the file
  system server). For this reason, a user of the VFS library should
  request synchronization before calling 'stat()' or 'close()'. To make
  sure that a file system server has processed all write request packets
  which a client submitted before the synchronization request,
  synchronization is now requested at the file system server with a
  synchronization packet instead of an RPC function. Because of this
  change, the synchronization interface of the VFS library is now split
  into 'queue_sync()' and 'complete_sync()' functions.

Fixes #2399
This commit is contained in:
Christian Prochaska
2017-08-15 20:51:53 +02:00
committed by Christian Helmuth
parent 8312950e2f
commit b0935ef9b2
49 changed files with 4361 additions and 2307 deletions

View File

@ -159,7 +159,7 @@ struct Cli_monitor::Main
Vfs::Dir_file_system _root_dir { _env, _heap, _vfs_config(), io_response_handler,
_global_file_system_factory };
Subsystem_config_registry _subsystem_config_registry { _root_dir, _heap };
Subsystem_config_registry _subsystem_config_registry { _root_dir, _heap, _env.ep() };
template <typename T>
struct Registered : T

View File

@ -32,8 +32,9 @@ class Cli_monitor::Subsystem_config_registry
private:
Vfs::File_system &_fs;
Genode::Allocator &_alloc;
Vfs::File_system &_fs;
Genode::Allocator &_alloc;
Genode::Entrypoint &_ep;
enum { CONFIG_BUF_SIZE = 32*1024 };
char _config_buf[CONFIG_BUF_SIZE];
@ -62,9 +63,10 @@ class Cli_monitor::Subsystem_config_registry
/**
* Constructor
*/
Subsystem_config_registry(Vfs::File_system &fs, Genode::Allocator &alloc)
Subsystem_config_registry(Vfs::File_system &fs, Genode::Allocator &alloc,
Genode::Entrypoint &ep)
:
_fs(fs), _alloc(alloc)
_fs(fs), _alloc(alloc), _ep(ep)
{ }
/**
@ -103,8 +105,17 @@ class Cli_monitor::Subsystem_config_registry
}
Vfs::file_size out_count = 0;
Vfs::File_io_service::Read_result read_result =
handle->fs().read(handle, _config_buf, sizeof(_config_buf), out_count);
handle->fs().queue_read(handle, sizeof(_config_buf));
Vfs::File_io_service::Read_result read_result;
while ((read_result =
handle->fs().complete_read(handle, _config_buf,
sizeof(_config_buf),
out_count)) ==
Vfs::File_io_service::READ_QUEUED)
_ep.wait_and_dispatch_one_io_signal();
if (read_result != Vfs::File_io_service::READ_OK) {
error("could not read '", path, "', err=", (int)read_result);
@ -133,22 +144,35 @@ class Cli_monitor::Subsystem_config_registry
{
using Genode::error;
Vfs::Vfs_handle *dir_handle;
if (_fs.opendir(_subsystems_path(), false, &dir_handle, _alloc) !=
Vfs::Directory_service::OPENDIR_OK) {
error("could not access directory '", _subsystems_path(), "'");
return;
}
/* iterate over the directory entries */
for (unsigned i = 0;; i++) {
Vfs::Directory_service::Dirent dirent;
Vfs::Directory_service::Dirent_result dirent_result =
_fs.dirent(_subsystems_path(), i, dirent);
dir_handle->seek(i * sizeof(dirent));
dir_handle->fs().queue_read(dir_handle, sizeof(dirent));
if (dirent_result != Vfs::Directory_service::DIRENT_OK) {
error("could not access directory '", _subsystems_path(), "'");
Vfs::file_size out_count;
while (dir_handle->fs().complete_read(dir_handle,
(char*)&dirent,
sizeof(dirent),
out_count) ==
Vfs::File_io_service::READ_QUEUED)
_ep.wait_and_dispatch_one_io_signal();
if (dirent.type == Vfs::Directory_service::DIRENT_TYPE_END) {
_fs.close(dir_handle);
return;
}
if (dirent.type == Vfs::Directory_service::DIRENT_TYPE_END)
return;
unsigned const subsystem_suffix = _subsystem_suffix(dirent);
/* if file has a matching suffix, apply 'fn' */
@ -163,6 +187,8 @@ class Cli_monitor::Subsystem_config_registry
} catch (Nonexistent_subsystem_config) { }
}
}
_fs.close(dir_handle);
}
};

View File

@ -53,62 +53,272 @@ class Vfs::Block_file_system : public Single_file_system
Genode::Signal_context _signal_context;
Genode::Signal_context_capability _source_submit_cap;
file_size _block_io(file_size nr, void *buf, file_size sz,
bool write, bool bulk = false)
class Block_vfs_handle : public Single_vfs_handle
{
Block::Packet_descriptor::Opcode op;
op = write ? Block::Packet_descriptor::WRITE : Block::Packet_descriptor::READ;
private:
file_size packet_size = bulk ? sz : _block_size;
file_size packet_count = bulk ? (sz / _block_size) : 1;
Genode::Allocator &_alloc;
Label &_label;
Lock &_lock;
char *_block_buffer;
unsigned &_block_buffer_count;
Genode::Allocator_avl &_tx_block_alloc;
Block::Connection &_block;
Genode::size_t &_block_size;
Block::sector_t &_block_count;
Block::Session::Operations &_block_ops;
Block::Session::Tx::Source *_tx_source;
bool &_readable;
bool &_writeable;
Genode::Signal_receiver &_signal_receiver;
Genode::Signal_context &_signal_context;
Genode::Signal_context_capability &_source_submit_cap;
Block::Packet_descriptor packet;
file_size _block_io(file_size nr, void *buf, file_size sz,
bool write, bool bulk = false)
{
Block::Packet_descriptor::Opcode op;
op = write ? Block::Packet_descriptor::WRITE : Block::Packet_descriptor::READ;
/* sanity check */
if (packet_count > _block_buffer_count) {
packet_size = _block_buffer_count * _block_size;
packet_count = _block_buffer_count;
}
file_size packet_size = bulk ? sz : _block_size;
file_size packet_count = bulk ? (sz / _block_size) : 1;
while (true) {
try {
Lock::Guard guard(_lock);
Block::Packet_descriptor packet;
packet = _tx_source->alloc_packet(packet_size);
break;
} catch (Block::Session::Tx::Source::Packet_alloc_failed) {
if (!_tx_source->ready_to_submit())
_signal_receiver.wait_for_signal();
else {
if (packet_count > 1) {
packet_size /= 2;
packet_count /= 2;
/* sanity check */
if (packet_count > _block_buffer_count) {
packet_size = _block_buffer_count * _block_size;
packet_count = _block_buffer_count;
}
while (true) {
try {
Lock::Guard guard(_lock);
packet = _tx_source->alloc_packet(packet_size);
break;
} catch (Block::Session::Tx::Source::Packet_alloc_failed) {
if (!_tx_source->ready_to_submit())
_signal_receiver.wait_for_signal();
else {
if (packet_count > 1) {
packet_size /= 2;
packet_count /= 2;
}
}
}
}
Lock::Guard guard(_lock);
Block::Packet_descriptor p(packet, op, nr, packet_count);
if (write)
Genode::memcpy(_tx_source->packet_content(p), buf, packet_size);
_tx_source->submit_packet(p);
p = _tx_source->get_acked_packet();
if (!p.succeeded()) {
Genode::error("Could not read block(s)");
_tx_source->release_packet(p);
return 0;
}
if (!write)
Genode::memcpy(buf, _tx_source->packet_content(p), packet_size);
_tx_source->release_packet(p);
return packet_size;
}
}
Lock::Guard guard(_lock);
Block::Packet_descriptor p(packet, op, nr, packet_count);
public:
if (write)
Genode::memcpy(_tx_source->packet_content(p), buf, packet_size);
Block_vfs_handle(Directory_service &ds,
File_io_service &fs,
Genode::Allocator &alloc,
Label &label,
Lock &lock,
char *block_buffer,
unsigned &block_buffer_count,
Genode::Allocator_avl &tx_block_alloc,
Block::Connection &block,
Genode::size_t &block_size,
Block::sector_t &block_count,
Block::Session::Operations &block_ops,
Block::Session::Tx::Source *tx_source,
bool &readable,
bool &writeable,
Genode::Signal_receiver &signal_receiver,
Genode::Signal_context &signal_context,
Genode::Signal_context_capability &source_submit_cap)
: Single_vfs_handle(ds, fs, alloc, 0),
_alloc(alloc),
_label(label),
_lock(lock),
_block_buffer(block_buffer),
_block_buffer_count(block_buffer_count),
_tx_block_alloc(tx_block_alloc),
_block(block),
_block_size(block_size),
_block_count(block_count),
_block_ops(block_ops),
_tx_source(tx_source),
_readable(readable),
_writeable(writeable),
_signal_receiver(signal_receiver),
_signal_context(signal_context),
_source_submit_cap(source_submit_cap)
{ }
_tx_source->submit_packet(p);
p = _tx_source->get_acked_packet();
Read_result read(char *dst, file_size count,
file_size &out_count) override
{
if (!_readable) {
Genode::error("block device is not readable");
return READ_ERR_INVALID;
}
if (!p.succeeded()) {
Genode::error("Could not read block(s)");
_tx_source->release_packet(p);
return 0;
}
file_size seek_offset = seek();
if (!write)
Genode::memcpy(buf, _tx_source->packet_content(p), packet_size);
file_size read = 0;
while (count > 0) {
file_size displ = 0;
file_size length = 0;
file_size nbytes = 0;
file_size blk_nr = seek_offset / _block_size;
_tx_source->release_packet(p);
return packet_size;
}
displ = seek_offset % _block_size;
if ((displ + count) > _block_size)
length = (_block_size - displ);
else
length = count;
/*
* We take a shortcut and read the blocks all at once if the
* offset is aligned on a block boundary and we the count is a
* multiple of the block size, e.g. 4K reads will be read at
* once.
*
* XXX this is quite hackish because we have to omit partial
* blocks at the end.
*/
if (displ == 0 && (count % _block_size) >= 0 && !(count < _block_size)) {
file_size bytes_left = count - (count % _block_size);
nbytes = _block_io(blk_nr, dst + read, bytes_left, false, true);
if (nbytes == 0) {
Genode::error("error while reading block:", blk_nr, " from block device");
return READ_ERR_INVALID;
}
read += nbytes;
count -= nbytes;
seek_offset += nbytes;
continue;
}
nbytes = _block_io(blk_nr, _block_buffer, _block_size, false);
if ((unsigned)nbytes != _block_size) {
Genode::error("error while reading block:", blk_nr, " from block device");
return READ_ERR_INVALID;
}
Genode::memcpy(dst + read, _block_buffer + displ, length);
read += length;
count -= length;
seek_offset += length;
}
out_count = read;
return READ_OK;
}
Write_result write(char const *buf, file_size count,
file_size &out_count) override
{
if (!_writeable) {
Genode::error("block device is not writeable");
return WRITE_ERR_INVALID;
}
file_size seek_offset = seek();
file_size written = 0;
while (count > 0) {
file_size displ = 0;
file_size length = 0;
file_size nbytes = 0;
file_size blk_nr = seek_offset / _block_size;
displ = seek_offset % _block_size;
if ((displ + count) > _block_size)
length = (_block_size - displ);
else
length = count;
/*
* We take a shortcut and write as much as possible without
* using the block buffer if the offset is aligned on a block
* boundary and the count is a multiple of the block size,
* e.g. 4K writes will be written at once.
*
* XXX this is quite hackish because we have to omit partial
* blocks at the end.
*/
if (displ == 0 && (count % _block_size) >= 0 && !(count < _block_size)) {
file_size bytes_left = count - (count % _block_size);
nbytes = _block_io(blk_nr, (void*)(buf + written),
bytes_left, true, true);
if (nbytes == 0) {
Genode::error("error while write block:", blk_nr, " to block device");
return WRITE_ERR_INVALID;
}
written += nbytes;
count -= nbytes;
seek_offset += nbytes;
continue;
}
/*
* The offset is not aligned on a block boundary. Therefore
* we need to read the block to the block buffer first and
* put the buffer content at the right offset before we can
* write the whole block back. In addition if length is less
* than block size, we also have to read the block first.
*/
if (displ > 0 || length < _block_size)
_block_io(blk_nr, _block_buffer, _block_size, false);
Genode::memcpy(_block_buffer + displ, buf + written, length);
nbytes = _block_io(blk_nr, _block_buffer, _block_size, true);
if ((unsigned)nbytes != _block_size) {
Genode::error("error while writing block:", blk_nr, " to block_device");
return WRITE_ERR_INVALID;
}
written += length;
count -= length;
seek_offset += length;
}
out_count = written;
return WRITE_OK;
}
bool read_ready() { return true; }
};
public:
@ -155,6 +365,31 @@ class Vfs::Block_file_system : public Single_file_system
** Directory service interface **
*********************************/
Open_result open(char const *path, unsigned,
Vfs_handle **out_handle,
Allocator &alloc) override
{
if (!_single_file(path))
return OPEN_ERR_UNACCESSIBLE;
*out_handle = new (alloc) Block_vfs_handle(*this, *this, alloc,
_label, _lock,
_block_buffer,
_block_buffer_count,
_tx_block_alloc,
_block,
_block_size,
_block_count,
_block_ops,
_tx_source,
_readable,
_writeable,
_signal_receiver,
_signal_context,
_source_submit_cap);
return OPEN_OK;
}
Stat_result stat(char const *path, Stat &out) override
{
Stat_result const result = Single_file_system::stat(path, out);
@ -167,153 +402,6 @@ class Vfs::Block_file_system : public Single_file_system
** File I/O service interface **
********************************/
Write_result write(Vfs_handle *vfs_handle, char const *buf,
file_size count, file_size &out_count) override
{
if (!_writeable) {
Genode::error("block device is not writeable");
return WRITE_ERR_INVALID;
}
file_size seek_offset = vfs_handle->seek();
file_size written = 0;
while (count > 0) {
file_size displ = 0;
file_size length = 0;
file_size nbytes = 0;
file_size blk_nr = seek_offset / _block_size;
displ = seek_offset % _block_size;
if ((displ + count) > _block_size)
length = (_block_size - displ);
else
length = count;
/*
* We take a shortcut and write as much as possible without
* using the block buffer if the offset is aligned on a block
* boundary and the count is a multiple of the block size,
* e.g. 4K writes will be written at once.
*
* XXX this is quite hackish because we have to omit partial
* blocks at the end.
*/
if (displ == 0 && (count % _block_size) >= 0 && !(count < _block_size)) {
file_size bytes_left = count - (count % _block_size);
nbytes = _block_io(blk_nr, (void*)(buf + written),
bytes_left, true, true);
if (nbytes == 0) {
Genode::error("error while write block:", blk_nr, " to block device");
return WRITE_ERR_INVALID;
}
written += nbytes;
count -= nbytes;
seek_offset += nbytes;
continue;
}
/*
* The offset is not aligned on a block boundary. Therefore
* we need to read the block to the block buffer first and
* put the buffer content at the right offset before we can
* write the whole block back. In addition if length is less
* than block size, we also have to read the block first.
*/
if (displ > 0 || length < _block_size)
_block_io(blk_nr, _block_buffer, _block_size, false);
Genode::memcpy(_block_buffer + displ, buf + written, length);
nbytes = _block_io(blk_nr, _block_buffer, _block_size, true);
if ((unsigned)nbytes != _block_size) {
Genode::error("error while writing block:", blk_nr, " to block_device");
return WRITE_ERR_INVALID;
}
written += length;
count -= length;
seek_offset += length;
}
out_count = written;
return WRITE_OK;
}
Read_result read(Vfs_handle *vfs_handle, char *dst, file_size count,
file_size &out_count) override
{
if (!_readable) {
Genode::error("block device is not readable");
return READ_ERR_INVALID;
}
file_size seek_offset = vfs_handle->seek();
file_size read = 0;
while (count > 0) {
file_size displ = 0;
file_size length = 0;
file_size nbytes = 0;
file_size blk_nr = seek_offset / _block_size;
displ = seek_offset % _block_size;
if ((displ + count) > _block_size)
length = (_block_size - displ);
else
length = count;
/*
* We take a shortcut and read the blocks all at once if the
* offset is aligned on a block boundary and we the count is a
* multiple of the block size, e.g. 4K reads will be read at
* once.
*
* XXX this is quite hackish because we have to omit partial
* blocks at the end.
*/
if (displ == 0 && (count % _block_size) >= 0 && !(count < _block_size)) {
file_size bytes_left = count - (count % _block_size);
nbytes = _block_io(blk_nr, dst + read, bytes_left, false, true);
if (nbytes == 0) {
Genode::error("error while reading block:", blk_nr, " from block device");
return READ_ERR_INVALID;
}
read += nbytes;
count -= nbytes;
seek_offset += nbytes;
continue;
}
nbytes = _block_io(blk_nr, _block_buffer, _block_size, false);
if ((unsigned)nbytes != _block_size) {
Genode::error("error while reading block:", blk_nr, " from block device");
return READ_ERR_INVALID;
}
Genode::memcpy(dst + read, _block_buffer + displ, length);
read += length;
count -= length;
seek_offset += length;
}
out_count = read;
return READ_OK;
}
bool read_ready(Vfs_handle *) override { return true; }
Ftruncate_result ftruncate(Vfs_handle *vfs_handle, file_size) override
{
return FTRUNCATE_OK;

File diff suppressed because it is too large Load Diff

View File

@ -29,6 +29,64 @@ class Vfs::Inline_file_system : public Single_file_system
char const * const _base;
file_size const _size;
class Inline_vfs_handle : public Single_vfs_handle
{
private:
char const * const _base;
file_size const _size;
public:
Inline_vfs_handle(Directory_service &ds,
File_io_service &fs,
Genode::Allocator &alloc,
char const * const base,
file_size const size)
: Single_vfs_handle(ds, fs, alloc, 0),
_base(base), _size(size)
{ }
Read_result read(char *dst, file_size count,
file_size &out_count) override
{
/* file read limit is the size of the dataspace */
file_size const max_size = _size;
/* current read offset */
file_size const read_offset = seek();
/* maximum read offset, clamped to dataspace size */
file_size const end_offset = min(count + read_offset, max_size);
/* source address within the dataspace */
char const *src = _base + read_offset;
/* check if end of file is reached */
if (read_offset >= end_offset) {
out_count = 0;
return READ_OK;
}
/* copy-out bytes from ROM dataspace */
file_size const num_bytes = end_offset - read_offset;
memcpy(dst, src, num_bytes);
out_count = num_bytes;
return READ_OK;
}
Write_result write(char const *src, file_size count,
file_size &out_count) override
{
out_count = 0;
return WRITE_ERR_INVALID;
}
bool read_ready() { return true; }
};
public:
Inline_file_system(Genode::Env&,
@ -48,56 +106,24 @@ class Vfs::Inline_file_system : public Single_file_system
** Directory service interface **
********************************/
Open_result open(char const *path, unsigned,
Vfs_handle **out_handle,
Allocator &alloc) override
{
if (!_single_file(path))
return OPEN_ERR_UNACCESSIBLE;
*out_handle = new (alloc) Inline_vfs_handle(*this, *this, alloc,
_base, _size);
return OPEN_OK;
}
Stat_result stat(char const *path, Stat &out) override
{
Stat_result result = Single_file_system::stat(path, out);
out.size = _size;
return result;
}
/********************************
** File I/O service interface **
********************************/
Write_result write(Vfs_handle *, char const *, file_size,
file_size &count_out) override
{
count_out = 0;
return WRITE_ERR_INVALID;
}
Read_result read(Vfs_handle *vfs_handle, char *dst, file_size count,
file_size &out_count) override
{
/* file read limit is the size of the dataspace */
file_size const max_size = _size;
/* current read offset */
file_size const read_offset = vfs_handle->seek();
/* maximum read offset, clamped to dataspace size */
file_size const end_offset = min(count + read_offset, max_size);
/* source address within the dataspace */
char const *src = _base + read_offset;
/* check if end of file is reached */
if (read_offset >= end_offset) {
out_count = 0;
return READ_OK;
}
/* copy-out bytes from ROM dataspace */
file_size const num_bytes = end_offset - read_offset;
memcpy(dst, src, num_bytes);
out_count = num_bytes;
return READ_OK;
}
bool read_ready(Vfs_handle *) override { return true; }
};
#endif /* _INCLUDE__VFS__INLINE_FILE_SYSTEM_H_ */

View File

@ -46,6 +46,50 @@ class Vfs::Log_file_system : public Single_file_system
Genode::Log_session &_log;
class Log_vfs_handle : public Single_vfs_handle
{
private:
Genode::Log_session &_log;
public:
Log_vfs_handle(Directory_service &ds,
File_io_service &fs,
Genode::Allocator &alloc,
Genode::Log_session &log)
: Single_vfs_handle(ds, fs, alloc, 0),
_log(log) { }
Read_result read(char *dst, file_size count,
file_size &out_count) override
{
out_count = 0;
return READ_OK;
}
Write_result write(char const *src, file_size count,
file_size &out_count) override
{
out_count = count;
/* count does not include the trailing '\0' */
while (count > 0) {
char tmp[Genode::Log_session::MAX_STRING_LEN];
int const curr_count = min(count, sizeof(tmp) - 1);
memcpy(tmp, src, curr_count);
tmp[curr_count > 0 ? curr_count : 0] = 0;
_log.write(tmp);
count -= curr_count;
src += curr_count;
}
return WRITE_OK;
}
bool read_ready() { return false; }
};
public:
Log_file_system(Genode::Env &env,
@ -61,37 +105,21 @@ class Vfs::Log_file_system : public Single_file_system
static const char *name() { return "log"; }
char const *type() override { return "log"; }
/********************************
** File I/O service interface **
********************************/
/*********************************
** Directory service interface **
*********************************/
Write_result write(Vfs_handle *, char const *src, file_size count,
file_size &out_count) override
Open_result open(char const *path, unsigned,
Vfs_handle **out_handle,
Allocator &alloc) override
{
out_count = count;
if (!_single_file(path))
return OPEN_ERR_UNACCESSIBLE;
/* count does not include the trailing '\0' */
while (count > 0) {
char tmp[Genode::Log_session::MAX_STRING_LEN];
int const curr_count = min(count, sizeof(tmp) - 1);
memcpy(tmp, src, curr_count);
tmp[curr_count > 0 ? curr_count : 0] = 0;
_log.write(tmp);
count -= curr_count;
src += curr_count;
}
return WRITE_OK;
*out_handle = new (alloc) Log_vfs_handle(*this, *this, alloc,
_log);
return OPEN_OK;
}
Read_result read(Vfs_handle *, char *, file_size,
file_size &out_count) override
{
out_count = 0;
return READ_OK;
}
bool read_ready(Vfs_handle *) override { return false; }
};
#endif /* _INCLUDE__VFS__LOG_FILE_SYSTEM_H_ */

View File

@ -33,28 +33,51 @@ struct Vfs::Null_file_system : Single_file_system
static char const *name() { return "null"; }
char const *type() override { return "null"; }
struct Null_vfs_handle : Single_vfs_handle
{
Null_vfs_handle(Directory_service &ds,
File_io_service &fs,
Genode::Allocator &alloc)
: Single_vfs_handle(ds, fs, alloc, 0) { }
Read_result read(char *dst, file_size count,
file_size &out_count) override
{
out_count = 0;
return READ_OK;
}
Write_result write(char const *src, file_size count,
file_size &out_count) override
{
out_count = count;
return WRITE_OK;
}
bool read_ready() { return false; }
};
/*********************************
** Directory service interface **
*********************************/
Open_result open(char const *path, unsigned,
Vfs_handle **out_handle,
Allocator &alloc) override
{
if (!_single_file(path))
return OPEN_ERR_UNACCESSIBLE;
*out_handle = new (alloc) Null_vfs_handle(*this, *this, alloc);
return OPEN_OK;
}
/********************************
** File I/O service interface **
********************************/
Write_result write(Vfs_handle *handle, char const *, file_size count,
file_size &out_count) override
{
out_count = count;
return WRITE_OK;
}
Read_result read(Vfs_handle *vfs_handle, char *, file_size,
file_size &out_count) override
{
out_count = 0;
return READ_OK;
}
bool read_ready(Vfs_handle *) override { return false; }
Ftruncate_result ftruncate(Vfs_handle *vfs_handle, file_size) override
{
return FTRUNCATE_OK;

View File

@ -57,6 +57,7 @@ class Vfs_ram::Node : public Genode::Avl_node<Node>, public Genode::Lock
private:
char _name[MAX_NAME_LEN];
int _open_handles = 0;
/**
* Generate unique inode number
@ -81,6 +82,46 @@ class Vfs_ram::Node : public Genode::Avl_node<Node>, public Genode::Lock
virtual Vfs::file_size length() = 0;
/**
* Increment reference counter
*/
void open() { ++_open_handles; }
bool close_but_keep()
{
if (--_open_handles < 0) {
inode = 0;
return false;
}
return true;
}
virtual size_t read(char *dst, size_t len, file_size seek_offset)
{
Genode::error("Vfs_ram::Node::read() called");
return 0;
}
virtual Vfs::File_io_service::Read_result complete_read(char *dst,
file_size count,
file_size seek_offset,
file_size &out_count)
{
Genode::error("Vfs_ram::Node::complete_read() called");
return Vfs::File_io_service::READ_ERR_INVALID;
}
virtual size_t write(char const *src, size_t len, file_size seek_offset)
{
Genode::error("Vfs_ram::Node::write() called");
return 0;
}
virtual void truncate(file_size size)
{
Genode::error("Vfs_ram::Node::truncate() called");
}
/************************
** Avl node interface **
************************/
@ -128,7 +169,6 @@ class Vfs_ram::Node : public Genode::Avl_node<Node>, public Genode::Lock
~Guard() { node->unlock(); }
};
};
@ -143,28 +183,13 @@ class Vfs_ram::File : public Vfs_ram::Node
Chunk_level_0 _chunk;
file_size _length = 0;
int _open_handles = 0;
public:
File(char const *name, Allocator &alloc)
: Node(name), _chunk(alloc, 0) { }
/**
* Increment reference counter
*/
void open() { ++_open_handles; }
bool close_but_keep()
{
if (--_open_handles < 0) {
inode = 0;
return false;
}
return true;
}
size_t read(char *dst, size_t len, file_size seek_offset)
size_t read(char *dst, size_t len, file_size seek_offset) override
{
file_size const chunk_used_size = _chunk.used_size();
@ -198,7 +223,16 @@ class Vfs_ram::File : public Vfs_ram::Node
return len;
}
size_t write(char const *src, size_t len, file_size seek_offset)
Vfs::File_io_service::Read_result complete_read(char *dst,
file_size count,
file_size seek_offset,
file_size &out_count) override
{
out_count = read(dst, count, seek_offset);
return Vfs::File_io_service::READ_OK;
}
size_t write(char const *src, size_t len, file_size seek_offset) override
{
if (seek_offset == (file_size)(~0))
seek_offset = _chunk.used_size();
@ -221,7 +255,7 @@ class Vfs_ram::File : public Vfs_ram::Node
file_size length() { return _length; }
void truncate(file_size size)
void truncate(file_size size) override
{
if (size < _chunk.used_size())
_chunk.truncate(size);
@ -246,6 +280,13 @@ class Vfs_ram::Symlink : public Vfs_ram::Node
void set(char const *target, size_t len)
{
for (size_t i = 0; i < len; ++i) {
if (target[i] == '\0') {
len = i;
break;
}
}
_len = len;
memcpy(_target, target, _len);
}
@ -256,6 +297,25 @@ class Vfs_ram::Symlink : public Vfs_ram::Node
memcpy(buf, _target, out);
return out;
}
Vfs::File_io_service::Read_result complete_read(char *dst,
file_size count,
file_size seek_offset,
file_size &out_count) override
{
out_count = get(dst, count);
return Vfs::File_io_service::READ_OK;
}
size_t write(char const *src, size_t len, file_size) override
{
if (len > MAX_PATH_LEN)
return 0;
set(src, len);
return len;
}
};
@ -305,35 +365,51 @@ class Vfs_ram::Directory : public Vfs_ram::Node
file_size length() override { return _count; }
void dirent(file_offset index, Directory_service::Dirent &dirent)
Vfs::File_io_service::Read_result complete_read(char *dst,
file_size count,
file_size seek_offset,
file_size &out_count) override
{
typedef Vfs::Directory_service::Dirent Dirent;
if (count < sizeof(Dirent))
return Vfs::File_io_service::READ_ERR_INVALID;
file_offset index = seek_offset / sizeof(Dirent);
Dirent *dirent = (Dirent*)dst;
*dirent = Dirent();
out_count = sizeof(Dirent);
Node *node = _entries.first();
if (node) node = node->index(index);
if (!node) {
dirent.type = Directory_service::DIRENT_TYPE_END;
return;
dirent->type = Directory_service::DIRENT_TYPE_END;
return Vfs::File_io_service::READ_OK;
}
dirent.fileno = node->inode;
strncpy(dirent.name, node->name(), sizeof(dirent.name));
dirent->fileno = node->inode;
strncpy(dirent->name, node->name(), sizeof(dirent->name));
File *file = dynamic_cast<File *>(node);
if (file) {
dirent.type = Directory_service::DIRENT_TYPE_FILE;
return;
dirent->type = Directory_service::DIRENT_TYPE_FILE;
return Vfs::File_io_service::READ_OK;
}
Directory *dir = dynamic_cast<Directory *>(node);
if (dir) {
dirent.type = Directory_service::DIRENT_TYPE_DIRECTORY;
return;
dirent->type = Directory_service::DIRENT_TYPE_DIRECTORY;
return Vfs::File_io_service::READ_OK;
}
Symlink *symlink = dynamic_cast<Symlink *>(node);
if (symlink) {
dirent.type = Directory_service::DIRENT_TYPE_SYMLINK;
return;
dirent->type = Directory_service::DIRENT_TYPE_SYMLINK;
return Vfs::File_io_service::READ_OK;
}
return Vfs::File_io_service::READ_ERR_INVALID;
}
};
@ -344,15 +420,15 @@ class Vfs::Ram_file_system : public Vfs::File_system
struct Ram_vfs_handle : Vfs_handle
{
Vfs_ram::File &file;
Vfs_ram::Node &node;
Ram_vfs_handle(Ram_file_system &fs,
Allocator &alloc,
int status_flags,
Vfs_ram::File &node)
: Vfs_handle(fs, fs, alloc, status_flags), file(node)
Vfs_ram::Node &node)
: Vfs_handle(fs, fs, alloc, status_flags), node(node)
{
file.open();
node.open();
}
};
@ -459,27 +535,6 @@ class Vfs::Ram_file_system : public Vfs::File_system
char const *leaf_path(char const *path) {
return lookup(path) ? path : nullptr; }
Mkdir_result mkdir(char const *path, unsigned mode) override
{
using namespace Vfs_ram;
Directory *parent = lookup_parent(path);
if (!parent) return MKDIR_ERR_NO_ENTRY;
Node::Guard guard(parent);
char const *name = basename(path);
if (strlen(name) >= MAX_NAME_LEN)
return MKDIR_ERR_NAME_TOO_LONG;
if (parent->child(name)) return MKDIR_ERR_EXISTS;
try { parent->adopt(new (_alloc) Directory(name)); }
catch (Out_of_memory) { return MKDIR_ERR_NO_SPACE; }
return MKDIR_OK;
}
Open_result open(char const *path, unsigned mode,
Vfs_handle **handle,
Allocator &alloc) override
@ -514,14 +569,104 @@ class Vfs::Ram_file_system : public Vfs::File_system
return OPEN_OK;
}
Opendir_result opendir(char const *path, bool create,
Vfs_handle **handle,
Allocator &alloc) override
{
using namespace Vfs_ram;
Directory *parent = lookup_parent(path);
if (!parent) return OPENDIR_ERR_LOOKUP_FAILED;
Node::Guard guard(parent);
char const *name = basename(path);
Directory *dir;
if (create) {
if (strlen(name) >= MAX_NAME_LEN)
return OPENDIR_ERR_NAME_TOO_LONG;
if (parent->child(name))
return OPENDIR_ERR_NODE_ALREADY_EXISTS;
try {
dir = new (_alloc) Directory(name);
} catch (Out_of_memory) { return OPENDIR_ERR_NO_SPACE; }
parent->adopt(dir);
} else {
Node *node = lookup(path);
if (!node) return OPENDIR_ERR_LOOKUP_FAILED;
dir = dynamic_cast<Directory *>(node);
if (!dir) return OPENDIR_ERR_LOOKUP_FAILED;
}
*handle = new (alloc) Ram_vfs_handle(*this, alloc,
Ram_vfs_handle::STATUS_RDONLY,
*dir);
return OPENDIR_OK;
}
Openlink_result openlink(char const *path, bool create,
Vfs_handle **handle, Allocator &alloc) override
{
using namespace Vfs_ram;
Directory *parent = lookup_parent(path);
if (!parent) return OPENLINK_ERR_LOOKUP_FAILED;
Node::Guard guard(parent);
char const *name = basename(path);
Symlink *link;
Node *node = parent->child(name);
if (create) {
if (node)
return OPENLINK_ERR_NODE_ALREADY_EXISTS;
if (strlen(name) >= MAX_NAME_LEN)
return OPENLINK_ERR_NAME_TOO_LONG;
try { link = new (_alloc) Symlink(name); }
catch (Out_of_memory) { return OPENLINK_ERR_NO_SPACE; }
link->lock();
parent->adopt(link);
link->unlock();
} else {
if (!node) return OPENLINK_ERR_LOOKUP_FAILED;
Node::Guard guard(node);
link = dynamic_cast<Symlink *>(node);
if (!link) return OPENLINK_ERR_LOOKUP_FAILED;
}
*handle = new (alloc) Ram_vfs_handle(*this, alloc,
Ram_vfs_handle::STATUS_RDWR,
*link);
return OPENLINK_OK;
}
void close(Vfs_handle *vfs_handle) override
{
Ram_vfs_handle *ram_handle =
static_cast<Ram_vfs_handle *>(vfs_handle);
if (ram_handle) {
if (!ram_handle->file.close_but_keep())
destroy(_alloc, &ram_handle->file);
if (!ram_handle->node.close_but_keep())
destroy(_alloc, &ram_handle->node);
destroy(vfs_handle->alloc(), ram_handle);
}
}
@ -560,80 +705,6 @@ class Vfs::Ram_file_system : public Vfs::File_system
return STAT_ERR_NO_ENTRY;
}
Dirent_result dirent(char const *path, file_offset index, Dirent &dirent) override
{
using namespace Vfs_ram;
Node *node = lookup(path);
if (!node) return DIRENT_ERR_INVALID_PATH;
Node::Guard guard(node);
Directory *dir = dynamic_cast<Directory *>(node);
if (!dir) return DIRENT_ERR_INVALID_PATH;
dir->dirent(index, dirent);
return DIRENT_OK;
}
Symlink_result symlink(char const *target, char const *path) override
{
using namespace Vfs_ram;
auto const target_len = strlen(target);
if (target_len > MAX_PATH_LEN)
return SYMLINK_ERR_NAME_TOO_LONG;
Symlink *link;
Directory *parent = lookup_parent(path);
if (!parent) return SYMLINK_ERR_NO_ENTRY;
Node::Guard guard(parent);
char const *name = basename(path);
Node *node = parent->child(name);
if (node) {
node->lock();
link = dynamic_cast<Symlink *>(node);
if (!link) {
node->unlock();
return SYMLINK_ERR_EXISTS;
}
} else {
if (strlen(name) >= MAX_NAME_LEN)
return SYMLINK_ERR_NAME_TOO_LONG;
try { link = new (_alloc) Symlink(name); }
catch (Out_of_memory) { return SYMLINK_ERR_NO_SPACE; }
link->lock();
parent->adopt(link);
}
if (*target)
link->set(target, target_len);
link->unlock();
return SYMLINK_OK;
}
Readlink_result readlink(char const *path, char *buf,
file_size buf_size, file_size &out_len) override
{
using namespace Vfs_ram;
Directory *parent = lookup_parent(path);
if (!parent) return READLINK_ERR_NO_ENTRY;
Node::Guard parent_guard(parent);
Node *node = parent->child(basename(path));
if (!node) return READLINK_ERR_NO_ENTRY;
Node::Guard guard(node);
Symlink *link = dynamic_cast<Symlink *>(node);
if (!link) return READLINK_ERR_NO_ENTRY;
out_len = link->get(buf, buf_size);
return READLINK_OK;
}
Rename_result rename(char const *from, char const *to) override
{
using namespace Vfs_ram;
@ -748,26 +819,23 @@ class Vfs::Ram_file_system : public Vfs::File_system
Ram_vfs_handle const *handle =
static_cast<Ram_vfs_handle *>(vfs_handle);
Vfs_ram::Node::Guard guard(&handle->file);
out = handle->file.write(buf, len, handle->seek());
Vfs_ram::Node::Guard guard(&handle->node);
out = handle->node.write(buf, len, handle->seek());
return WRITE_OK;
}
Read_result read(Vfs_handle *vfs_handle,
char *buf, file_size len,
file_size &out) override
Read_result complete_read(Vfs_handle *vfs_handle, char *dst, file_size count,
file_size &out_count) override
{
if ((vfs_handle->status_flags() & OPEN_MODE_ACCMODE) == OPEN_MODE_WRONLY)
return READ_ERR_INVALID;
out_count = 0;
Ram_vfs_handle const *handle =
static_cast<Ram_vfs_handle *>(vfs_handle);
Vfs_ram::Node::Guard guard(&handle->file);
Vfs_ram::Node::Guard guard(&handle->node);
out = handle->file.read(buf, len, handle->seek());
return READ_OK;
return handle->node.complete_read(dst, count, handle->seek(), out_count);
}
bool read_ready(Vfs_handle *) override { return true; }
@ -780,9 +848,9 @@ class Vfs::Ram_file_system : public Vfs::File_system
Ram_vfs_handle const *handle =
static_cast<Ram_vfs_handle *>(vfs_handle);
Vfs_ram::Node::Guard guard(&handle->file);
Vfs_ram::Node::Guard guard(&handle->node);
try { handle->file.truncate(len); }
try { handle->node.truncate(len); }
catch (Vfs_ram::Out_of_memory) { return FTRUNCATE_ERR_NO_SPACE; }
return FTRUNCATE_OK;
}

View File

@ -46,6 +46,60 @@ class Vfs::Rom_file_system : public Single_file_system
Genode::Attached_rom_dataspace _rom;
class Rom_vfs_handle : public Single_vfs_handle
{
private:
Genode::Attached_rom_dataspace &_rom;
public:
Rom_vfs_handle(Directory_service &ds,
File_io_service &fs,
Genode::Allocator &alloc,
Genode::Attached_rom_dataspace &rom)
: Single_vfs_handle(ds, fs, alloc, 0), _rom(rom) { }
Read_result read(char *dst, file_size count,
file_size &out_count) override
{
/* file read limit is the size of the dataspace */
file_size const max_size = _rom.size();
/* current read offset */
file_size const read_offset = seek();
/* maximum read offset, clamped to dataspace size */
file_size const end_offset = min(count + read_offset, max_size);
/* source address within the dataspace */
char const *src = _rom.local_addr<char>() + read_offset;
/* check if end of file is reached */
if (read_offset >= end_offset) {
out_count = 0;
return READ_OK;
}
/* copy-out bytes from ROM dataspace */
file_size const num_bytes = end_offset - read_offset;
memcpy(dst, src, num_bytes);
out_count = num_bytes;
return READ_OK;
}
Write_result write(char const *src, file_size count,
file_size &out_count) override
{
out_count = 0;
return WRITE_ERR_INVALID;
}
bool read_ready() { return true; }
};
public:
Rom_file_system(Genode::Env &env,
@ -65,27 +119,23 @@ class Vfs::Rom_file_system : public Single_file_system
** Directory-service interface **
********************************/
Dataspace_capability dataspace(char const *path) override
{
return _rom.cap();
}
/*
* Overwrite the default open function to update the ROM dataspace
* each time when opening the corresponding file.
*/
Open_result open(char const *path, unsigned,
Vfs_handle **out_handle,
Allocator &alloc) override
{
Open_result const result =
Single_file_system::open(path, 0, out_handle, alloc);
if (!_single_file(path))
return OPEN_ERR_UNACCESSIBLE;
_rom.update();
return result;
*out_handle = new (alloc) Rom_vfs_handle(*this, *this, alloc, _rom);
return OPEN_OK;
}
Dataspace_capability dataspace(char const *path) override
{
return _rom.cap();
}
/********************************
** File I/O service interface **
@ -100,50 +150,6 @@ class Vfs::Rom_file_system : public Single_file_system
return result;
}
/********************************
** File I/O service interface **
********************************/
Write_result write(Vfs_handle *, char const *, file_size,
file_size &count_out) override
{
count_out = 0;
return WRITE_ERR_INVALID;
}
Read_result read(Vfs_handle *vfs_handle, char *dst, file_size count,
file_size &out_count) override
{
/* file read limit is the size of the dataspace */
file_size const max_size = _rom.size();
/* current read offset */
file_size const read_offset = vfs_handle->seek();
/* maximum read offset, clamped to dataspace size */
file_size const end_offset = min(count + read_offset, max_size);
/* source address within the dataspace */
char const *src = _rom.local_addr<char>() + read_offset;
/* check if end of file is reached */
if (read_offset >= end_offset) {
out_count = 0;
return READ_OK;
}
/* copy-out bytes from ROM dataspace */
file_size const num_bytes = end_offset - read_offset;
memcpy(dst, src, num_bytes);
out_count = num_bytes;
return READ_OK;
}
bool read_ready(Vfs_handle *) override { return true; }
};
#endif /* _INCLUDE__VFS__ROM_FILE_SYSTEM_H_ */

View File

@ -28,6 +28,63 @@ class Vfs::Rtc_file_system : public Single_file_system
Rtc::Connection _rtc;
class Rtc_vfs_handle : public Single_vfs_handle
{
private:
Rtc::Connection &_rtc;
public:
Rtc_vfs_handle(Directory_service &ds,
File_io_service &fs,
Genode::Allocator &alloc,
Rtc::Connection &rtc)
: Single_vfs_handle(ds, fs, alloc, 0),
_rtc(rtc) { }
/**
* Read the current time from the Rtc session
*
* On each read the current time is queried and afterwards formated
* as '%Y-%m-%d %H:%M\n'.
*/
Read_result read(char *dst, file_size count,
file_size &out_count) override
{
enum { TIMESTAMP_LEN = 17 };
if (seek() >= TIMESTAMP_LEN) {
out_count = 0;
return READ_OK;
}
Rtc::Timestamp ts = _rtc.current_time();
char buf[TIMESTAMP_LEN+1];
char *b = buf;
unsigned n = Genode::snprintf(buf, sizeof(buf), "%04u-%02u-%02u %02u:%02u\n",
ts.year, ts.month, ts.day, ts.hour, ts.minute);
n -= seek();
b += seek();
file_size len = count > n ? n : count;
Genode::memcpy(dst, b, len);
out_count = len;
return READ_OK;
}
Write_result write(char const *src, file_size count,
file_size &out_count) override
{
return WRITE_ERR_IO;
}
bool read_ready() { return true; }
};
public:
Rtc_file_system(Genode::Env &env,
@ -46,6 +103,18 @@ class Vfs::Rtc_file_system : public Single_file_system
** Directory-service interface **
*********************************/
Open_result open(char const *path, unsigned,
Vfs_handle **out_handle,
Allocator &alloc) override
{
if (!_single_file(path))
return OPEN_ERR_UNACCESSIBLE;
*out_handle = new (alloc) Rtc_vfs_handle(*this, *this, alloc,
_rtc);
return OPEN_OK;
}
Stat_result stat(char const *path, Stat &out) override
{
Stat_result result = Single_file_system::stat(path, out);
@ -53,53 +122,6 @@ class Vfs::Rtc_file_system : public Single_file_system
return result;
}
/********************************
** File I/O service interface **
********************************/
Write_result write(Vfs_handle *, char const *, file_size,
file_size &) override
{
return WRITE_ERR_IO;
}
/**
* Read the current time from the Rtc session
*
* On each read the current time is queried and afterwards formated
* as '%Y-%m-%d %H:%M\n'.
*/
Read_result read(Vfs_handle *vfs_handle, char *dst, file_size count,
file_size &out_count) override
{
enum { TIMESTAMP_LEN = 17 };
file_size seek = vfs_handle->seek();
if (seek >= TIMESTAMP_LEN) {
out_count = 0;
return READ_OK;
}
Rtc::Timestamp ts = _rtc.current_time();
char buf[TIMESTAMP_LEN+1];
char *b = buf;
unsigned n = Genode::snprintf(buf, sizeof(buf), "%04u-%02u-%02u %02u:%02u\n",
ts.year, ts.month, ts.day, ts.hour, ts.minute);
n -= seek;
b += seek;
file_size len = count > n ? n : count;
Genode::memcpy(dst, b, len);
out_count = len;
return READ_OK;
}
bool read_ready(Vfs_handle *) override { return true; }
};
#endif /* _INCLUDE__VFS__RTC_FILE_SYSTEM_H_ */

View File

@ -47,28 +47,30 @@ class Vfs::Symlink_file_system : public Single_file_system
** Directory-service interface **
*********************************/
Symlink_result symlink(char const *from, char const *to) override {
return SYMLINK_ERR_EXISTS; }
Readlink_result readlink(char const *path,
char *buf,
file_size buf_len,
file_size &out_len) override
{
if (!_single_file(path))
return READLINK_ERR_NO_ENTRY;
out_len = min(buf_len, (file_size)_target.length()-1);
memcpy(buf, _target.string(), out_len);
if (out_len < buf_len)
buf[out_len] = '\0';
return READLINK_OK;
}
Open_result open(char const *, unsigned, Vfs_handle **out_handle,
Allocator&) override {
return OPEN_ERR_UNACCESSIBLE; }
void close(Vfs_handle *) override { }
Openlink_result openlink(char const *path, bool create,
Vfs_handle **out_handle, Allocator &alloc) override
{
if (!_single_file(path))
return OPENLINK_ERR_LOOKUP_FAILED;
if (create)
return OPENLINK_ERR_NODE_ALREADY_EXISTS;
*out_handle = new (alloc) Vfs_handle(*this, *this, alloc, 0);
return OPENLINK_OK;
}
void close(Vfs_handle *vfs_handle) override
{
if (!vfs_handle)
return;
destroy(vfs_handle->alloc(), vfs_handle);
}
/********************************
@ -79,8 +81,15 @@ class Vfs::Symlink_file_system : public Single_file_system
file_size &) override {
return WRITE_ERR_INVALID; }
Read_result read(Vfs_handle *, char *, file_size, file_size &) override {
return READ_ERR_INVALID; }
Read_result complete_read(Vfs_handle *, char *buf, file_size buf_len,
file_size &out_len) override
{
out_len = min(buf_len, (file_size)_target.length()-1);
memcpy(buf, _target.string(), out_len);
if (out_len < buf_len)
buf[out_len] = '\0';
return READ_OK;
}
bool read_ready(Vfs_handle *) override { return false; }

View File

@ -86,23 +86,126 @@ class Vfs::Tar_file_system : public File_system
void *data() const { return (char *)this + BLOCK_LEN; }
};
class Node;
class Tar_vfs_handle : public Vfs_handle
{
private:
protected:
Record const *_record;
Node const *_node;
public:
Tar_vfs_handle(File_system &fs, Allocator &alloc, int status_flags, Record const *record)
: Vfs_handle(fs, fs, alloc, status_flags), _record(record)
Tar_vfs_handle(File_system &fs, Allocator &alloc, int status_flags,
Node const *node)
: Vfs_handle(fs, fs, alloc, status_flags), _node(node)
{ }
Record const *record() const { return _record; }
virtual Read_result read(char *dst, file_size count,
file_size &out_count) = 0;
};
struct Tar_vfs_file_handle : Tar_vfs_handle
{
using Tar_vfs_handle::Tar_vfs_handle;
Read_result read(char *dst, file_size count,
file_size &out_count) override
{
file_size const record_size = _node->record->size();
file_size const record_bytes_left = record_size >= seek()
? record_size - seek() : 0;
count = min(record_bytes_left, count);
char const *data = (char *)_node->record->data() + seek();
memcpy(dst, data, count);
out_count = count;
return READ_OK;
}
};
struct Tar_vfs_dir_handle : Tar_vfs_handle
{
using Tar_vfs_handle::Tar_vfs_handle;
Read_result read(char *dst, file_size count,
file_size &out_count) override
{
if (count < sizeof(Dirent))
return READ_ERR_INVALID;
Dirent *dirent = (Dirent*)dst;
/* initialize */
*dirent = Dirent();
file_offset index = seek() / sizeof(Dirent);
Node const *node = _node->lookup_child(index);
if (!node)
return READ_OK;
dirent->fileno = (Genode::addr_t)node;
Record const *record = node->record;
while (record && (record->type() == Record::TYPE_HARDLINK)) {
Tar_file_system &tar_fs = static_cast<Tar_file_system&>(fs());
Node const *target = tar_fs.dereference(record->linked_name());
record = target ? target->record : 0;
}
if (record) {
switch (record->type()) {
case Record::TYPE_FILE:
dirent->type = DIRENT_TYPE_FILE; break;
case Record::TYPE_SYMLINK:
dirent->type = DIRENT_TYPE_SYMLINK; break;
case Record::TYPE_DIR:
dirent->type = DIRENT_TYPE_DIRECTORY; break;
default:
Genode::error("unhandled record type ", record->type(), " "
"for ", node->name);
}
} else {
/* If no record exists, assume it is a directory */
dirent->type = DIRENT_TYPE_DIRECTORY;
}
strncpy(dirent->name, node->name, sizeof(dirent->name));
out_count = sizeof(Dirent);
return READ_OK;
}
};
struct Tar_vfs_symlink_handle : Tar_vfs_handle
{
using Tar_vfs_handle::Tar_vfs_handle;
Read_result read(char *buf, file_size buf_size,
file_size &out_count) override
{
Record const *record = _node->record;
file_size const count = min(buf_size, 100ULL);
memcpy(buf, record->linked_name(), count);
out_count = count;
return READ_OK;
}
};
struct Scanner_policy_path_element
{
static bool identifier_char(char c, unsigned /* i */)
@ -430,52 +533,6 @@ class Vfs::Tar_file_system : public File_system
return STAT_OK;
}
Dirent_result dirent(char const *path, file_offset index, Dirent &out) override
{
Node const *node = dereference(path);
if (!node)
return DIRENT_ERR_INVALID_PATH;
node = node->lookup_child(index);
if (!node) {
out.type = DIRENT_TYPE_END;
return DIRENT_OK;
}
out.fileno = (Genode::addr_t)node;
Record const *record = node->record;
while (record && (record->type() == Record::TYPE_HARDLINK)) {
Node const *target = dereference(record->linked_name());
record = target ? target->record : 0;
}
if (record) {
switch (record->type()) {
case Record::TYPE_FILE:
out.type = DIRENT_TYPE_FILE; break;
case Record::TYPE_SYMLINK:
out.type = DIRENT_TYPE_SYMLINK; break;
case Record::TYPE_DIR:
out.type = DIRENT_TYPE_DIRECTORY; break;
default:
Genode::error("unhandled record type ", record->type(), " "
"for ", node->name);
}
} else {
/* If no record exists, assume it is a directory */
out.type = DIRENT_TYPE_DIRECTORY;
}
strncpy(out.name, node->name, sizeof(out.name));
return DIRENT_OK;
}
Unlink_result unlink(char const *path) override
{
Node const *node = dereference(path);
@ -485,24 +542,6 @@ class Vfs::Tar_file_system : public File_system
return UNLINK_ERR_NO_PERM;
}
Readlink_result readlink(char const *path, char *buf, file_size buf_size,
file_size &out_len) override
{
Node const *node = dereference(path);
Record const *record = node ? node->record : 0;
if (!record || (record->type() != Record::TYPE_SYMLINK))
return READLINK_ERR_NO_ENTRY;
file_size const count = min(buf_size, 100ULL);
memcpy(buf, record->linked_name(), count);
out_len = count;
return READLINK_OK;
}
Rename_result rename(char const *from, char const *to) override
{
if (_root_node.lookup(from) || _root_node.lookup(to))
@ -510,16 +549,6 @@ class Vfs::Tar_file_system : public File_system
return RENAME_ERR_NO_ENTRY;
}
Mkdir_result mkdir(char const *, unsigned) override
{
return MKDIR_ERR_NO_PERM;
}
Symlink_result symlink(char const *, char const *) override
{
return SYMLINK_ERR_NO_ENTRY;
}
file_size num_dirent(char const *path) override
{
return _cached_num_dirent.num_dirent(path);
@ -548,17 +577,46 @@ class Vfs::Tar_file_system : public File_system
return node ? path : 0;
}
Open_result open(char const *path, unsigned, Vfs_handle **out_handle, Genode::Allocator& alloc) override
Open_result open(char const *path, unsigned, Vfs_handle **out_handle,
Genode::Allocator& alloc) override
{
Node const *node = dereference(path);
if (!node || !node->record || node->record->type() != Record::TYPE_FILE)
return OPEN_ERR_UNACCESSIBLE;
*out_handle = new (alloc) Tar_vfs_handle(*this, alloc, 0, node->record);
*out_handle = new (alloc) Tar_vfs_file_handle(*this, alloc, 0, node);
return OPEN_OK;
}
Opendir_result opendir(char const *path, bool create,
Vfs_handle **out_handle,
Genode::Allocator& alloc) override
{
Node const *node = dereference(path);
if (!node ||
(node->record && (node->record->type() != Record::TYPE_DIR)))
return OPENDIR_ERR_LOOKUP_FAILED;
*out_handle = new (alloc) Tar_vfs_dir_handle(*this, alloc, 0, node);
return OPENDIR_OK;
}
Openlink_result openlink(char const *path, bool create,
Vfs_handle **out_handle, Allocator &alloc)
{
Node const *node = dereference(path);
if (!node || !node->record ||
node->record->type() != Record::TYPE_SYMLINK)
return OPENLINK_ERR_LOOKUP_FAILED;
*out_handle = new (alloc) Tar_vfs_symlink_handle(*this, alloc, 0, node);
return OPENLINK_OK;
}
void close(Vfs_handle *vfs_handle) override
{
Tar_vfs_handle *tar_handle =
@ -587,24 +645,17 @@ class Vfs::Tar_file_system : public File_system
return WRITE_ERR_INVALID;
}
Read_result read(Vfs_handle *vfs_handle, char *dst, file_size count,
file_size &out_count) override
Read_result complete_read(Vfs_handle *vfs_handle, char *dst,
file_size count, file_size &out_count) override
{
Tar_vfs_handle const *handle = static_cast<Tar_vfs_handle *>(vfs_handle);
out_count = 0;
file_size const record_size = handle->record()->size();
Tar_vfs_handle *handle = static_cast<Tar_vfs_handle *>(vfs_handle);
file_size const record_bytes_left = record_size >= handle->seek()
? record_size - handle->seek() : 0;
if (!handle)
return READ_ERR_INVALID;
count = min(record_bytes_left, count);
char const *data = (char *)handle->record()->data() + handle->seek();
memcpy(dst, data, count);
out_count = count;
return READ_OK;
return handle->read(dst, count, out_count);
}
Ftruncate_result ftruncate(Vfs_handle *handle, file_size) override

View File

@ -137,20 +137,6 @@ class Vfs::Terminal_file_system : public Single_file_system
return WRITE_OK;
}
Read_result read(Vfs_handle *, char *dst, file_size count,
file_size &out_count) override
{
out_count = _terminal.read(dst, count);
return READ_OK;
}
bool queue_read(Vfs_handle *vfs_handle, char *dst, file_size count,
Read_result &out_result, file_size &out_count) override
{
out_result = _read(vfs_handle, dst, count, out_count);
return true;
}
Read_result complete_read(Vfs_handle *vfs_handle, char *dst, file_size count,
file_size &out_count) override
{

View File

@ -33,28 +33,48 @@ struct Vfs::Zero_file_system : Single_file_system
static char const *name() { return "zero"; }
char const *type() override { return "zero"; }
/********************************
** File I/O service interface **
********************************/
Write_result write(Vfs_handle *, char const *, file_size count,
file_size &count_out) override
struct Zero_vfs_handle : Single_vfs_handle
{
count_out = count;
Zero_vfs_handle(Directory_service &ds,
File_io_service &fs,
Genode::Allocator &alloc)
: Single_vfs_handle(ds, fs, alloc, 0) { }
return WRITE_OK;
Read_result read(char *dst, file_size count,
file_size &out_count) override
{
memset(dst, 0, count);
out_count = count;
return READ_OK;
}
Write_result write(char const *src, file_size count,
file_size &out_count) override
{
out_count = count;
return WRITE_OK;
}
bool read_ready() { return true; }
};
/*********************************
** Directory service interface **
*********************************/
Open_result open(char const *path, unsigned,
Vfs_handle **out_handle,
Allocator &alloc) override
{
if (!_single_file(path))
return OPEN_ERR_UNACCESSIBLE;
*out_handle = new (alloc) Zero_vfs_handle(*this, *this, alloc);
return OPEN_OK;
}
Read_result read(Vfs_handle *vfs_handle, char *dst, file_size count,
file_size &out_count) override
{
memset(dst, 0, count);
out_count = count;
return READ_OK;
}
bool read_ready(Vfs_handle *) override { return true; }
};
#endif /* _INCLUDE__VFS__ZERO_FILE_SYSTEM_H_ */

View File

@ -56,8 +56,19 @@ class Fs_log::Session_component : public Genode::Rpc_object<Genode::Log_session>
~Session_component()
{
_fs.sync(_handle);
_fs.close(_handle);
/* sync */
File_system::Session::Tx::Source &source = *_fs.tx();
File_system::Packet_descriptor packet = source.get_acked_packet();
if (packet.operation() == File_system::Packet_descriptor::SYNC)
_fs.close(packet.handle());
packet = File_system::Packet_descriptor(
packet, _handle, File_system::Packet_descriptor::SYNC, 0, 0);
source.submit_packet(packet);
}
@ -78,9 +89,13 @@ class Fs_log::Session_component : public Genode::Rpc_object<Genode::Log_session>
File_system::Session::Tx::Source &source = *_fs.tx();
File_system::Packet_descriptor packet(
source.get_acked_packet(),
_handle, File_system::Packet_descriptor::WRITE,
File_system::Packet_descriptor packet = source.get_acked_packet();
if (packet.operation() == File_system::Packet_descriptor::SYNC)
_fs.close(packet.handle());
packet = File_system::Packet_descriptor(
packet, _handle, File_system::Packet_descriptor::WRITE,
msg_len, File_system::SEEK_TAIL);
char *buf = source.packet_content(packet);

View File

@ -34,25 +34,29 @@ namespace Fs_report {
typedef Genode::Path<Session_label::capacity()> Path;
static bool create_parent_dir(Vfs::Directory_service &vfs, Path const &child)
static bool create_parent_dir(Vfs::Directory_service &vfs, Path const &child,
Genode::Allocator &alloc)
{
typedef Vfs::Directory_service::Mkdir_result Mkdir_result;
typedef Vfs::Directory_service::Opendir_result Opendir_result;
Path parent = child;
parent.strip_last_element();
if (parent == "/")
return true;
Mkdir_result res = vfs.mkdir(parent.base(), 0);
if (res == Mkdir_result::MKDIR_ERR_NO_ENTRY) {
if (!create_parent_dir(vfs, parent))
Vfs_handle *dir_handle;
Opendir_result res = vfs.opendir(parent.base(), true, &dir_handle, alloc);
if (res == Opendir_result::OPENDIR_ERR_LOOKUP_FAILED) {
if (!create_parent_dir(vfs, parent, alloc))
return false;
res = vfs.mkdir(parent.base(), 0);
res = vfs.opendir(parent.base(), true, &dir_handle, alloc);
}
switch (res) {
case Mkdir_result::MKDIR_OK:
case Mkdir_result::MKDIR_ERR_EXISTS:
case Opendir_result::OPENDIR_OK:
vfs.close(dir_handle);
return true;
case Opendir_result::OPENDIR_ERR_NODE_ALREADY_EXISTS:
return true;
default:
return false;
@ -67,7 +71,8 @@ class Fs_report::Session_component : public Genode::Rpc_object<Report::Session>
Path _leaf_path;
Attached_ram_dataspace _ds;
Attached_ram_dataspace _ds;
Genode::Entrypoint &_ep;
Vfs_handle *_handle;
file_size _file_size = 0;
@ -80,13 +85,13 @@ class Fs_report::Session_component : public Genode::Rpc_object<Report::Session>
Vfs::File_system &vfs,
Genode::Session_label const &label,
size_t buffer_size)
: _ds(env.ram(), env.rm(), buffer_size)
: _ds(env.ram(), env.rm(), buffer_size), _ep(env.ep())
{
typedef Vfs::Directory_service::Open_result Open_result;
Path path = path_from_label<Path>(label.string());
create_parent_dir(vfs, path);
create_parent_dir(vfs, path, alloc);
Open_result res = vfs.open(
path.base(),
@ -155,7 +160,12 @@ class Fs_report::Session_component : public Genode::Rpc_object<Report::Session>
_success = true;
/* flush to notify watchers */
_handle->ds().sync(_leaf_path.base());
while (!_handle->fs().queue_sync(_handle))
_ep.wait_and_dispatch_one_io_signal();
while (_handle->fs().complete_sync(_handle) ==
Vfs::File_io_service::SYNC_QUEUED)
_ep.wait_and_dispatch_one_io_signal();
}
void response_sigh(Genode::Signal_context_capability) override { }

View File

@ -91,6 +91,16 @@ class Lx_fs::Session_component : public Session_rpc_object
case Packet_descriptor::READ_READY:
/* not supported */
break;
case Packet_descriptor::SYNC:
/**
* We could call sync(2) here but for now we forward just the
* reminder because besides testing, there is currently no
* use-case.
*/
Genode::warning("SYNC not implemented!");
break;
}
packet.length(res_length);
@ -327,13 +337,6 @@ class Lx_fs::Session_component : public Session_rpc_object
{
Genode::error(__func__, " not implemented");
}
/**
* We could call sync(2) here but for now we forward just the
* reminder because besides testing, there is currently no
* use-case.
*/
void sync(Node_handle) override { Genode::warning("sync() not implemented!"); }
};

View File

@ -95,6 +95,10 @@ class Ram_fs::Session_component : public File_system::Session_rpc_object
case Packet_descriptor::READ_READY:
/* not supported */
break;
case Packet_descriptor::SYNC:
open_node.node().notify_listeners();
break;
}
packet.length(res_length);
@ -150,7 +154,7 @@ class Ram_fs::Session_component : public File_system::Session_rpc_object
static void _assert_valid_path(char const *path)
{
if (!path || path[0] != '/') {
Genode::warning("malformed path ''", path, "'");
Genode::warning("malformed path '", Genode::Cstring(path), "'");
throw Lookup_failed();
}
}
@ -471,19 +475,6 @@ class Ram_fs::Session_component : public File_system::Session_rpc_object
throw Invalid_handle();
}
}
void sync(Node_handle handle) override
{
auto sync_fn = [&] (Open_node &open_node) {
open_node.node().notify_listeners();
};
try {
_open_node_registry.apply<Open_node>(handle, sync_fn);
} catch (Id_space<File_system::Node>::Unknown_id const &) {
throw Invalid_handle();
}
}
};

View File

@ -677,6 +677,10 @@ class Trace_fs::Session_component : public Session_rpc_object
case Packet_descriptor::READ_READY:
/* not supported */
break;
case Packet_descriptor::SYNC:
/* not supported */
break;
}
packet.length(res_length);

View File

@ -22,20 +22,6 @@ namespace File_system {
using namespace Vfs;
static inline void assert_mkdir(Directory_service::Mkdir_result r)
{
typedef Directory_service::Mkdir_result Result;
switch (r) {
case Result::MKDIR_ERR_NAME_TOO_LONG: throw Name_too_long();
case Result::MKDIR_ERR_NO_ENTRY: throw Lookup_failed();
case Result::MKDIR_ERR_NO_SPACE: throw No_space();
case Result::MKDIR_ERR_NO_PERM: throw Permission_denied();
case Result::MKDIR_ERR_EXISTS: throw Node_already_exists();
case Result::MKDIR_OK: break;
}
}
static inline void assert_open(Directory_service::Open_result r)
{
typedef Directory_service::Open_result Result;
@ -46,32 +32,41 @@ namespace File_system {
case Result::OPEN_ERR_NO_SPACE: throw No_space();
case Result::OPEN_ERR_NO_PERM: throw Permission_denied();
case Result::OPEN_ERR_EXISTS: throw Node_already_exists();
case Result::OPEN_ERR_OUT_OF_RAM: throw Out_of_ram();
case Result::OPEN_ERR_OUT_OF_CAPS: throw Out_of_caps();
case Result::OPEN_OK: break;
}
}
static inline void assert_symlink(Directory_service::Symlink_result r)
static inline void assert_opendir(Directory_service::Opendir_result r)
{
typedef Directory_service::Symlink_result Result;
typedef Directory_service::Opendir_result Result;
switch (r) {
case Result::SYMLINK_ERR_NAME_TOO_LONG: throw Invalid_name();
case Result::SYMLINK_ERR_NO_ENTRY: throw Lookup_failed();
case Result::SYMLINK_ERR_NO_SPACE: throw No_space();
case Result::SYMLINK_ERR_NO_PERM: throw Permission_denied();
case Result::SYMLINK_ERR_EXISTS: throw Node_already_exists();
case Result::SYMLINK_OK: break;
case Result::OPENDIR_ERR_LOOKUP_FAILED: throw Lookup_failed();
case Result::OPENDIR_ERR_NAME_TOO_LONG: throw Invalid_name();
case Result::OPENDIR_ERR_NODE_ALREADY_EXISTS: throw Node_already_exists();
case Result::OPENDIR_ERR_NO_SPACE: throw No_space();
case Result::OPENDIR_ERR_OUT_OF_RAM: throw Out_of_ram();
case Result::OPENDIR_ERR_OUT_OF_CAPS: throw Out_of_caps();
case Result::OPENDIR_ERR_PERMISSION_DENIED: throw Permission_denied();
case Result::OPENDIR_OK: break;
}
}
static inline void assert_readlink(Directory_service::Readlink_result r)
static inline void assert_openlink(Directory_service::Openlink_result r)
{
typedef Directory_service::Readlink_result Result;
typedef Directory_service::Openlink_result Result;
switch (r) {
case Result::READLINK_ERR_NO_ENTRY: throw Lookup_failed();
case Result::READLINK_ERR_NO_PERM: throw Permission_denied();
case Result::READLINK_OK: break;
case Result::OPENLINK_ERR_LOOKUP_FAILED: throw Lookup_failed();
case Result::OPENLINK_ERR_NAME_TOO_LONG: throw Invalid_name();
case Result::OPENLINK_ERR_NODE_ALREADY_EXISTS: throw Node_already_exists();
case Result::OPENLINK_ERR_NO_SPACE: throw No_space();
case Result::OPENLINK_ERR_OUT_OF_RAM: throw Out_of_ram();
case Result::OPENLINK_ERR_OUT_OF_CAPS: throw Out_of_caps();
case Result::OPENLINK_ERR_PERMISSION_DENIED: throw Permission_denied();
case Result::OPENLINK_OK: break;
}
}

View File

@ -43,7 +43,7 @@ namespace Vfs_server {
class Vfs_server::Session_component : public File_system::Session_rpc_object,
public File_io_handler
public Node_io_handler
{
private:
@ -113,13 +113,13 @@ class Vfs_server::Session_component : public File_system::Session_rpc_object,
** Packet-stream processing **
******************************/
struct Not_read_ready { };
struct Not_ready { };
struct Dont_ack { };
/**
* Perform packet operation
*
* \throw Not_read_ready
* \throw Not_ready
* \throw Dont_ack
*/
void _process_packet_op(Packet_descriptor &packet)
@ -142,46 +142,36 @@ class Vfs_server::Session_component : public File_system::Session_rpc_object,
case Packet_descriptor::READ:
try {
_apply(static_cast<File_handle>(packet.handle().value), [&] (File &node) {
_apply(packet.handle(), [&] (Node &node) {
if (!node.read_ready()) {
node.notify_read_ready(true);
throw Not_read_ready();
throw Not_ready();
}
if (node.mode&READ_ONLY)
res_length = node.read(_vfs, (char *)content, length, seek);
if (node.mode() & READ_ONLY)
res_length = node.read((char *)content, length, seek);
});
}
catch (Not_read_ready) { throw; }
catch (Operation_incomplete) { throw Not_read_ready(); }
catch (...) {
try {
_apply(packet.handle(), [&] (Node &node) {
if (!node.read_ready())
throw Not_read_ready();
if (node.mode&READ_ONLY)
res_length = node.read(_vfs, (char *)content, length, seek);
});
}
catch (Not_read_ready) { throw; }
catch (Operation_incomplete) { throw Not_read_ready(); }
catch (...) { }
}
catch (Not_ready) { throw; }
catch (Operation_incomplete) { throw Not_ready(); }
catch (...) { }
break;
case Packet_descriptor::WRITE:
try {
_apply(packet.handle(), [&] (Node &node) {
if (node.mode&WRITE_ONLY)
res_length = node.write(_vfs, (char const *)content, length, seek);
if (node.mode() & WRITE_ONLY)
res_length = node.write((char const *)content, length, seek);
});
} catch (Operation_incomplete) {
throw Not_ready();
} catch (...) { }
break;
case Packet_descriptor::READ_READY:
try {
_apply(static_cast<File_handle>(packet.handle().value), [] (File &node) {
if (!node.read_ready()) {
@ -197,6 +187,20 @@ class Vfs_server::Session_component : public File_system::Session_rpc_object,
case Packet_descriptor::CONTENT_CHANGED:
/* The VFS does not track file changes yet */
throw Dont_ack();
case Packet_descriptor::SYNC:
/**
* Sync the VFS and send any pending signals on the node.
*/
try {
_apply(packet.handle(), [&] (Node &node) {
node.sync();
});
} catch (Operation_incomplete) {
throw Not_ready();
} catch (...) { Genode::error("SYNC: unhandled exception"); }
break;
}
packet.length(res_length);
@ -208,7 +212,7 @@ class Vfs_server::Session_component : public File_system::Session_rpc_object,
try {
_process_packet_op(packet);
return true;
} catch (Not_read_ready) {
} catch (Not_ready) {
_backlog_packet = packet;
}
@ -218,8 +222,10 @@ class Vfs_server::Session_component : public File_system::Session_rpc_object,
bool _process_backlog()
{
/* indicate success if there's no backlog */
if (!_backlog_packet.size())
if (!_backlog_packet.size() &&
(_backlog_packet.operation() != Packet_descriptor::SYNC)) {
return true;
}
/* only start processing if acknowledgement is possible */
if (!tx_sink()->ready_to_ack())
@ -358,7 +364,7 @@ class Vfs_server::Session_component : public File_system::Session_rpc_object,
_tx.sigh_packet_avail(_process_packet_handler);
_tx.sigh_ready_to_ack(_process_packet_handler);
_root.construct(_node_space, vfs, root_path, false);
_root.construct(_node_space, vfs, _alloc, *this, root_path, false);
}
/**
@ -380,17 +386,27 @@ class Vfs_server::Session_component : public File_system::Session_rpc_object,
_ram.upgrade(new_quota);
}
/* File_io_handler interface */
void handle_file_io(File &file) override
/*
* Called by the IO response handler for events which are not
* node-specific, for example after 'release_packet()' to signal
* that a previously failed 'alloc_packet()' may succeed now.
*/
void handle_general_io()
{
if (file.notify_read_ready() && file.read_ready()
_process_packets();
}
/* Node_io_handler interface */
void handle_node_io(Node &node) override
{
if (node.notify_read_ready() && node.read_ready()
&& tx_sink()->ready_to_ack()) {
Packet_descriptor packet(Packet_descriptor(),
Node_handle { file.id().value },
Node_handle { node.id().value },
Packet_descriptor::READ_READY,
0, 0);
tx_sink()->acknowledge_packet(packet);
file.notify_read_ready(false);
node.notify_read_ready(false);
}
_process_packets();
}
@ -420,7 +436,8 @@ class Vfs_server::Session_component : public File_system::Session_rpc_object,
throw Lookup_failed();
Directory *dir;
try { dir = new (_alloc) Directory(_node_space, _vfs, path_str, create); }
try { dir = new (_alloc) Directory(_node_space, _vfs, _alloc,
*this, path_str, create); }
catch (Out_of_memory) { throw Out_of_ram(); }
return Dir_handle(dir->id().value);
@ -474,7 +491,8 @@ class Vfs_server::Session_component : public File_system::Session_rpc_object,
Node *node;
try { node = new (_alloc) Node(_node_space, path_str, STAT_ONLY); }
try { node = new (_alloc) Node(_node_space, path_str, STAT_ONLY,
*this); }
catch (Out_of_memory) { throw Out_of_ram(); }
return Node_handle { node->id().value };
@ -571,16 +589,6 @@ class Vfs_server::Session_component : public File_system::Session_rpc_object,
});
}
/**
* Sync the VFS and send any pending signals on the node.
*/
void sync(Node_handle handle) override
{
_apply(handle, [&] (Node &node) {
_vfs.sync(node.path());
});
}
void control(Node_handle, Control) override { }
};
@ -589,13 +597,35 @@ struct Vfs_server::Io_response_handler : Vfs::Io_response_handler
{
Session_registry &_session_registry;
bool _in_progress { false };
bool _handle_general_io { false };
Io_response_handler(Session_registry &session_registry)
: _session_registry(session_registry) { }
void handle_io_response(Vfs::Vfs_handle::Context *context) override
{
if (_in_progress) {
/* called recursively, context is nullptr in this case */
_handle_general_io = true;
return;
}
_in_progress = true;
if (Vfs_server::Node *node = static_cast<Vfs_server::Node *>(context))
node->handle_io_response();
else
_handle_general_io = true;
while (_handle_general_io) {
_handle_general_io = false;
_session_registry.for_each([ ] (Registered_session &r) {
r.handle_general_io();
});
}
_in_progress = false;
}
};

View File

@ -36,9 +36,9 @@ namespace Vfs_server {
typedef Genode::Id_space<Node> Node_space;
struct File_io_handler
struct Node_io_handler
{
virtual void handle_file_io(File &file) = 0;
virtual void handle_node_io(Node &node) = 0;
};
/**
@ -83,155 +83,27 @@ namespace Vfs_server {
}
struct Vfs_server::Node : File_system::Node_base, Node_space::Element,
Vfs::Vfs_handle::Context
class Vfs_server::Node : public File_system::Node_base, public Node_space::Element,
public Vfs::Vfs_handle::Context
{
Path const _path;
Mode const mode;
Node(Node_space &space, char const *node_path, Mode node_mode)
:
Node_space::Element(*this, space),
_path(node_path), mode(node_mode)
{ }
virtual ~Node() { }
char const *path() { return _path.base(); }
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 bool read_ready() { return false; }
virtual void handle_io_response() { }
};
struct Vfs_server::Symlink : Node
{
Symlink(Node_space &space,
Vfs::File_system &vfs,
char const *link_path,
Mode mode,
bool create)
: Node(space, link_path, mode)
{
if (create)
assert_symlink(vfs.symlink("", link_path));
}
/********************
** Node interface **
********************/
size_t read(Vfs::File_system &vfs, char *dst, size_t len, seek_off_t seek_offset)
{
Vfs::file_size res = 0;
vfs.readlink(path(), dst, len, res);
return res;
}
size_t write(Vfs::File_system &vfs, char const *src, size_t len, seek_off_t seek_offset)
{
/*
* if the symlink target is too long return a short result
* because a competent File_system client will error on a
* length mismatch
*/
if (len > MAX_PATH_LEN) {
return len >> 1;
}
/* ensure symlink gets something null-terminated */
Genode::String<MAX_PATH_LEN+1> target(Genode::Cstring(src, len));
size_t const target_len = target.length()-1;
switch (vfs.symlink(target.string(), path())) {
case Directory_service::SYMLINK_OK: break;
case Directory_service::SYMLINK_ERR_NAME_TOO_LONG:
return target_len >> 1;
default: return 0;
}
mark_as_updated();
notify_listeners();
return target_len;
}
bool read_ready() override { return true; }
};
class Vfs_server::File : public Node
{
private:
File_io_handler &_file_io_handler;
Vfs::Vfs_handle *_handle;
char const *_leaf_path; /* offset pointer to Node::_path */
bool _notify_read_ready = false;
enum class Op_state {
IDLE, READ_QUEUED
} op_state = Op_state::IDLE;
public:
File(Node_space &space,
Vfs::File_system &vfs,
Genode::Allocator &alloc,
File_io_handler &file_io_handler,
char const *file_path,
Mode fs_mode,
bool create)
:
Node(space, file_path, fs_mode),
_file_io_handler(file_io_handler)
enum Op_state { IDLE, READ_QUEUED, SYNC_QUEUED };
private:
Path const _path;
Mode const _mode;
bool _notify_read_ready = false;
protected:
Node_io_handler &_node_io_handler;
Vfs::Vfs_handle *_handle { nullptr };
Op_state op_state { Op_state::IDLE };
size_t _read(char *dst, size_t len, seek_off_t seek_offset)
{
unsigned vfs_mode =
(fs_mode-1) | (create ? Vfs::Directory_service::OPEN_MODE_CREATE : 0);
assert_open(vfs.open(file_path, vfs_mode, &_handle, alloc));
_leaf_path = vfs.leaf_path(path());
_handle->context = this;
}
~File() { _handle->ds().close(_handle); }
void truncate(file_size_t size)
{
assert_truncate(_handle->fs().ftruncate(_handle, size));
mark_as_updated();
}
void notify_read_ready(bool requested)
{
if (requested)
_handle->fs().notify_read_ready(_handle);
_notify_read_ready = requested;
}
bool notify_read_ready() const { return _notify_read_ready; }
/********************
** Node interface **
********************/
size_t read(Vfs::File_system&, char *dst, size_t len,
seek_off_t seek_offset) override
{
if (seek_offset == SEEK_TAIL) {
typedef Directory_service::Stat_result Result;
Vfs::Directory_service::Stat st;
/* if stat fails, try and see if the VFS will seek to the end */
seek_offset = (_handle->ds().stat(_leaf_path, st) == Result::STAT_OK) ?
((len < st.size) ? (st.size - len) : 0) : SEEK_TAIL;
}
_handle->seek(seek_offset);
typedef Vfs::File_io_service::Read_result Result;
@ -242,34 +114,14 @@ class Vfs_server::File : public Node
switch (op_state) {
case Op_state::IDLE:
if (!_handle->fs().queue_read(_handle, dst, len, out_result, out_count))
if (!_handle->fs().queue_read(_handle, len))
throw Operation_incomplete();
switch (out_result) {
case Result::READ_OK:
op_state = Op_state::IDLE;
return out_count;
case Result::READ_ERR_WOULD_BLOCK:
case Result::READ_ERR_AGAIN:
case Result::READ_ERR_INTERRUPT:
op_state = Op_state::IDLE;
throw Operation_incomplete();
case Result::READ_ERR_IO:
case Result::READ_ERR_INVALID:
op_state = Op_state::IDLE;
/* FIXME revise error handling */
return 0;
case Result::READ_QUEUED:
op_state = Op_state::READ_QUEUED;
break;
}
/* fall through */
case Op_state::READ_QUEUED:
out_result = _handle->fs().complete_read(_handle, dst, len, out_count);
out_result = _handle->fs().complete_read(_handle, dst, len,
out_count);
switch (out_result) {
case Result::READ_OK:
op_state = Op_state::IDLE;
@ -292,16 +144,206 @@ class Vfs_server::File : public Node
throw Operation_incomplete();
}
break;
case Op_state::SYNC_QUEUED:
throw Operation_incomplete();
}
return 0;
}
size_t write(Vfs::File_system&, char const *src, size_t len,
seek_off_t seek_offset) override
size_t _write(char const *src, size_t len,
seek_off_t seek_offset)
{
Vfs::file_size res = 0;
_handle->seek(seek_offset);
try {
_handle->fs().write(_handle, src, len, res);
} catch (Vfs::File_io_service::Insufficient_buffer) {
throw Operation_incomplete();
}
if (res)
mark_as_updated();
return res;
}
public:
Node(Node_space &space, char const *node_path, Mode node_mode,
Node_io_handler &node_io_handler)
:
Node_space::Element(*this, space),
_path(node_path), _mode(node_mode),
_node_io_handler(node_io_handler)
{ }
virtual ~Node() { }
char const *path() { return _path.base(); }
Mode mode() const { return _mode; }
virtual size_t read(char *dst, size_t len, seek_off_t seek_offset)
{ return 0; }
virtual size_t write(char const *src, size_t len,
seek_off_t seek_offset) { return 0; }
bool read_ready() { return _handle->fs().read_ready(_handle); }
void handle_io_response()
{
_node_io_handler.handle_node_io(*this);
}
void notify_read_ready(bool requested)
{
if (requested)
_handle->fs().notify_read_ready(_handle);
_notify_read_ready = requested;
}
bool notify_read_ready() const { return _notify_read_ready; }
void sync()
{
typedef Vfs::File_io_service::Sync_result Result;
Result out_result = Result::SYNC_OK;
switch (op_state) {
case Op_state::IDLE:
if (!_handle->fs().queue_sync(_handle))
throw Operation_incomplete();
/* fall through */
case Op_state::SYNC_QUEUED:
out_result = _handle->fs().complete_sync(_handle);
switch (out_result) {
case Result::SYNC_OK:
op_state = Op_state::IDLE;
return;
case Result::SYNC_QUEUED:
op_state = Op_state::SYNC_QUEUED;
throw Operation_incomplete();
}
break;
case Op_state::READ_QUEUED:
throw Operation_incomplete();
}
}
};
struct Vfs_server::Symlink : Node
{
Symlink(Node_space &space,
Vfs::File_system &vfs,
Genode::Allocator &alloc,
Node_io_handler &node_io_handler,
char const *link_path,
Mode mode,
bool create)
: Node(space, link_path, mode, node_io_handler)
{
assert_openlink(vfs.openlink(link_path, create, &_handle, alloc));
_handle->context = this;
}
/********************
** Node interface **
********************/
size_t read(char *dst, size_t len, seek_off_t seek_offset)
{
if (seek_offset != 0) {
/* partial read is not supported */
return 0;
}
return _read(dst, len, 0);
}
size_t write(char const *src, size_t len, seek_off_t seek_offset)
{
/*
* if the symlink target is too long return a short result
* because a competent File_system client will error on a
* length mismatch
*/
if (len > MAX_PATH_LEN) {
return len >> 1;
}
/* ensure symlink gets something null-terminated */
Genode::String<MAX_PATH_LEN+1> target(Genode::Cstring(src, len));
size_t const target_len = target.length()-1;
file_size out_count;
if (_handle->fs().write(_handle, target.string(), target_len, out_count) !=
File_io_service::WRITE_OK)
return 0;
mark_as_updated();
notify_listeners();
return out_count;
}
};
class Vfs_server::File : public Node
{
private:
char const *_leaf_path; /* offset pointer to Node::_path */
public:
File(Node_space &space,
Vfs::File_system &vfs,
Genode::Allocator &alloc,
Node_io_handler &node_io_handler,
char const *file_path,
Mode fs_mode,
bool create)
:
Node(space, file_path, fs_mode, node_io_handler)
{
unsigned vfs_mode =
(fs_mode-1) | (create ? Vfs::Directory_service::OPEN_MODE_CREATE : 0);
assert_open(vfs.open(file_path, vfs_mode, &_handle, alloc));
_leaf_path = vfs.leaf_path(path());
_handle->context = this;
}
~File() { _handle->ds().close(_handle); }
size_t read(char *dst, size_t len, seek_off_t seek_offset) override
{
if (seek_offset == SEEK_TAIL) {
typedef Directory_service::Stat_result Result;
Vfs::Directory_service::Stat st;
/* if stat fails, try and see if the VFS will seek to the end */
seek_offset = (_handle->ds().stat(_leaf_path, st) == Result::STAT_OK) ?
((len < st.size) ? (st.size - len) : 0) : SEEK_TAIL;
}
return _read(dst, len, seek_offset);
}
size_t write(char const *src, size_t len,
seek_off_t seek_offset) override
{
if (seek_offset == SEEK_TAIL) {
typedef Directory_service::Stat_result Result;
Vfs::Directory_service::Stat st;
@ -311,35 +353,35 @@ class Vfs_server::File : public Node
st.size : SEEK_TAIL;
}
_handle->seek(seek_offset);
_handle->fs().write(_handle, src, len, res);
if (res)
mark_as_updated();
return res;
return _write(src, len, seek_offset);
}
bool read_ready() override { return _handle->fs().read_ready(_handle); }
void handle_io_response() override
void truncate(file_size_t size)
{
_file_io_handler.handle_file_io(*this);
assert_truncate(_handle->fs().ftruncate(_handle, size));
mark_as_updated();
}
};
struct Vfs_server::Directory : Node
{
Directory(Node_space &space, Vfs::File_system &vfs, char const *dir_path, bool create)
: Node(space, dir_path, READ_ONLY)
Directory(Node_space &space,
Vfs::File_system &vfs,
Genode::Allocator &alloc,
Node_io_handler &node_io_handler,
char const *dir_path,
bool create)
: Node(space, dir_path, READ_ONLY, node_io_handler)
{
if (create)
assert_mkdir(vfs.mkdir(dir_path, 0));
assert_opendir(vfs.opendir(dir_path, create, &_handle, alloc));
_handle->context = this;
}
Node_space::Id file(Node_space &space,
Vfs::File_system &vfs,
Genode::Allocator &alloc,
File_io_handler &file_io_handler,
Node_io_handler &node_io_handler,
char const *file_path,
Mode mode,
bool create)
@ -350,7 +392,7 @@ struct Vfs_server::Directory : Node
File *file;
try {
file = new (alloc)
File(space, vfs, alloc, file_io_handler, path_str, mode, create);
File(space, vfs, alloc, node_io_handler, path_str, mode, create);
} catch (Out_of_memory) { throw Out_of_ram(); }
if (create)
@ -368,13 +410,9 @@ struct Vfs_server::Directory : Node
Path subpath(link_path, path());
char const *path_str = subpath.base();
if (!create) {
Vfs::file_size out;
assert_readlink(vfs.readlink(path_str, nullptr, 0, out));
}
Symlink *link;
try { link = new (alloc) Symlink(space, vfs, path_str, mode, create); }
try { link = new (alloc) Symlink(space, vfs, alloc, _node_io_handler,
path_str, mode, create); }
catch (Out_of_memory) { throw Out_of_ram(); }
if (create)
mark_as_updated();
@ -386,7 +424,7 @@ struct Vfs_server::Directory : Node
** Node interface **
********************/
size_t read(Vfs::File_system &vfs, char *dst, size_t len, seek_off_t seek_offset)
size_t read(char *dst, size_t len, seek_off_t seek_offset) override
{
Directory_service::Dirent vfs_dirent;
size_t blocksize = sizeof(File_system::Directory_entry);
@ -396,8 +434,10 @@ struct Vfs_server::Directory : Node
size_t remains = len;
while (remains >= blocksize) {
if (vfs.dirent(path(), index++, vfs_dirent)
!= Vfs::Directory_service::DIRENT_OK)
if ((_read((char*)&vfs_dirent, sizeof(vfs_dirent),
index * sizeof(vfs_dirent)) < sizeof(vfs_dirent)) ||
(vfs_dirent.type == Vfs::Directory_service::DIRENT_TYPE_END))
return len - remains;
File_system::Directory_entry *fs_dirent = (Directory_entry *)dst;
@ -422,7 +462,11 @@ struct Vfs_server::Directory : Node
return len - remains;
}
bool read_ready() override { return true; }
size_t write(char const *src, size_t len,
seek_off_t seek_offset) override
{
return 0;
}
};
#endif /* _VFS__NODE_H_ */

View File

@ -45,26 +45,6 @@
using namespace Genode;
inline void assert_mkdir(Vfs::Directory_service::Mkdir_result r)
{
typedef Vfs::Directory_service::Mkdir_result Result;
switch (r) {
case Result::MKDIR_OK: return;
case Result::MKDIR_ERR_EXISTS:
error("MKDIR_ERR_EXISTS"); break;
case Result::MKDIR_ERR_NO_ENTRY:
error("MKDIR_ERR_NO_ENTRY"); break;
case Result::MKDIR_ERR_NO_SPACE:
error("MKDIR_ERR_NO_SPACE"); break;
case Result::MKDIR_ERR_NO_PERM:
error("MKDIR_ERR_NO_PERM"); break;
case Result::MKDIR_ERR_NAME_TOO_LONG:
error("MKDIR_ERR_NAME_TOO_LONG"); break;
}
throw Exception();
}
inline void assert_open(Vfs::Directory_service::Open_result r)
{
typedef Vfs::Directory_service::Open_result Result;
@ -80,6 +60,33 @@ inline void assert_open(Vfs::Directory_service::Open_result r)
error("OPEN_ERR_NO_PERM"); break;
case Result::OPEN_ERR_EXISTS:
error("OPEN_ERR_EXISTS"); break;
case Result::OPEN_ERR_OUT_OF_RAM:
error("OPEN_ERR_OUT_OF_RAM"); break;
case Result::OPEN_ERR_OUT_OF_CAPS:
error("OPEN_ERR_OUT_OF_CAPS"); break;
}
throw Exception();
}
inline void assert_opendir(Vfs::Directory_service::Opendir_result r)
{
typedef Vfs::Directory_service::Opendir_result Result;
switch (r) {
case Result::OPENDIR_OK: return;
case Result::OPENDIR_ERR_LOOKUP_FAILED:
error("OPENDIR_ERR_LOOKUP_FAILED"); break;
case Result::OPENDIR_ERR_NAME_TOO_LONG:
error("OPENDIR_ERR_NAME_TOO_LONG"); break;
case Result::OPENDIR_ERR_NODE_ALREADY_EXISTS:
error("OPENDIR_ERR_NODE_ALREADY_EXISTS"); break;
case Result::OPENDIR_ERR_NO_SPACE:
error("OPENDIR_ERR_NO_SPACE"); break;
case Result::OPENDIR_ERR_OUT_OF_RAM:
error("OPENDIR_ERR_OUT_OF_RAM"); break;
case Result::OPENDIR_ERR_OUT_OF_CAPS:
error("OPENDIR_ERR_OUT_OF_CAPS"); break;
case Result::OPENDIR_ERR_PERMISSION_DENIED:
error("OPENDIR_ERR_PERMISSION_DENIED"); break;
}
throw Exception();
}
@ -163,7 +170,9 @@ struct Mkdir_test : public Stress_test
if (++depth > MAX_DEPTH) return;
path.append("/b");
assert_mkdir(vfs.mkdir(path.base(), 0));
Vfs::Vfs_handle *dir_handle;
assert_opendir(vfs.opendir(path.base(), true, &dir_handle, alloc));
vfs.close(dir_handle);
++count;
mkdir_b(depth);
}
@ -174,15 +183,19 @@ struct Mkdir_test : public Stress_test
size_t path_len = strlen(path.base());
Vfs::Vfs_handle *dir_handle;
path.append("/b");
assert_mkdir(vfs.mkdir(path.base(), 0));
assert_opendir(vfs.opendir(path.base(), true, &dir_handle, alloc));
vfs.close(dir_handle);
++count;
mkdir_b(depth);
path.base()[path_len] = '\0';
path.append("/a");
assert_mkdir(vfs.mkdir(path.base(), 0));
assert_opendir(vfs.opendir(path.base(), true, &dir_handle, alloc));
vfs.close(dir_handle);
++count;
mkdir_a(depth);
}
@ -266,6 +279,8 @@ struct Populate_test : public Stress_test
struct Write_test : public Stress_test
{
Genode::Entrypoint &_ep;
void write(int depth)
{
if (++depth > MAX_DEPTH) return;
@ -285,6 +300,10 @@ struct Write_test : public Stress_test
file_size n;
assert_write(handle->fs().write(
handle, path.base(), path_len, n));
handle->fs().queue_sync(handle);
while (handle->fs().complete_sync(handle) ==
Vfs::File_io_service::SYNC_QUEUED)
_ep.wait_and_dispatch_one_io_signal();
count += n;
}
@ -307,8 +326,9 @@ struct Write_test : public Stress_test
}
}
Write_test(Vfs::File_system &vfs, Genode::Allocator &alloc, char const *parent)
: Stress_test(vfs, alloc, parent)
Write_test(Vfs::File_system &vfs, Genode::Allocator &alloc,
char const *parent, Genode::Entrypoint &ep)
: Stress_test(vfs, alloc, parent), _ep(ep)
{
size_t path_len = strlen(path.base());
try {
@ -332,6 +352,8 @@ struct Write_test : public Stress_test
struct Read_test : public Stress_test
{
Genode::Entrypoint &_ep;
void read(int depth)
{
if (++depth > MAX_DEPTH) return;
@ -350,7 +372,17 @@ struct Read_test : public Stress_test
char tmp[MAX_PATH_LEN];
file_size n;
assert_read(handle->fs().read(handle, tmp, sizeof(tmp), n));
handle->fs().queue_read(handle, sizeof(tmp));
Vfs::File_io_service::Read_result read_result;
while ((read_result =
handle->fs().complete_read(handle, tmp, sizeof(tmp), n)) ==
Vfs::File_io_service::READ_QUEUED)
_ep.wait_and_dispatch_one_io_signal();
assert_read(read_result);
if (strcmp(path.base(), tmp, n))
error("read returned bad data");
count += n;
@ -375,8 +407,9 @@ struct Read_test : public Stress_test
}
}
Read_test(Vfs::File_system &vfs, Genode::Allocator &alloc, char const *parent)
: Stress_test(vfs, alloc, parent)
Read_test(Vfs::File_system &vfs, Genode::Allocator &alloc, char const *parent,
Genode::Entrypoint &ep)
: Stress_test(vfs, alloc, parent), _ep(ep)
{
size_t path_len = strlen(path.base());
try {
@ -400,14 +433,27 @@ struct Read_test : public Stress_test
struct Unlink_test : public Stress_test
{
Genode::Entrypoint &_ep;
void empty_dir(char const *path)
{
::Path subpath(path);
subpath.append("/");
Vfs::Vfs_handle *dir_handle;
assert_opendir(vfs.opendir(path, false, &dir_handle, alloc));
Vfs::Directory_service::Dirent dirent;
for (Vfs::file_size i = vfs.num_dirent(path); i;) {
vfs.dirent(path, --i, dirent);
dir_handle->seek(--i * sizeof(dirent));
dir_handle->fs().queue_read(dir_handle, sizeof(dirent));
Vfs::file_size out_count;
while (dir_handle->fs().complete_read(dir_handle, (char*)&dirent,
sizeof(dirent), out_count) ==
Vfs::File_io_service::READ_QUEUED)
_ep.wait_and_dispatch_one_io_signal();
subpath.append(dirent.name);
switch (dirent.type) {
case Vfs::Directory_service::DIRENT_TYPE_END:
@ -428,10 +474,13 @@ struct Unlink_test : public Stress_test
subpath.strip_last_element();
}
}
vfs.close(dir_handle);
}
Unlink_test(Vfs::File_system &vfs, Genode::Allocator &alloc, char const *parent)
: Stress_test(vfs, alloc, parent)
Unlink_test(Vfs::File_system &vfs, Genode::Allocator &alloc,
char const *parent, Genode::Entrypoint &ep)
: Stress_test(vfs, alloc, parent), _ep(ep)
{
typedef Vfs::Directory_service::Unlink_result Result;
try {
@ -485,6 +534,20 @@ void Component::construct(Genode::Env &env)
Vfs::Dir_file_system vfs_root(env, heap, config_xml.sub_node("vfs"),
io_response_handler,
global_file_system_factory);
Vfs::Vfs_handle *vfs_root_handle;
vfs_root.opendir("/", false, &vfs_root_handle, heap);
auto vfs_root_sync = [&] ()
{
while (!vfs_root_handle->fs().queue_sync(vfs_root_handle))
env.ep().wait_and_dispatch_one_io_signal();
while (vfs_root_handle->fs().complete_sync(vfs_root_handle) ==
Vfs::File_io_service::SYNC_QUEUED)
env.ep().wait_and_dispatch_one_io_signal();
};
char path[Vfs::MAX_PATH_LEN];
MAX_DEPTH = config_xml.attribute_value("depth", 16U);
@ -507,13 +570,15 @@ void Component::construct(Genode::Env &env)
for (int i = 0; i < ROOT_TREE_COUNT; ++i) {
snprintf(path, 3, "/%d", i);
vfs_root.mkdir(path, 0);
Vfs::Vfs_handle *dir_handle;
vfs_root.opendir(path, true, &dir_handle, heap);
vfs_root.close(dir_handle);
Mkdir_test test(vfs_root, heap, path);
count += test.wait();
}
elapsed_ms = timer.elapsed_ms() - elapsed_ms;
vfs_root.sync("/");
vfs_root_sync();
log("created ",count," empty directories, ",
(elapsed_ms*1000)/count,"μs/op , ",
@ -537,7 +602,7 @@ void Component::construct(Genode::Env &env)
elapsed_ms = timer.elapsed_ms() - elapsed_ms;
vfs_root.sync("/");
vfs_root_sync();
log("created ",count," empty files, ",
(elapsed_ms*1000)/count,"μs/op, ",
@ -561,14 +626,14 @@ void Component::construct(Genode::Env &env)
for (int i = 0; i < ROOT_TREE_COUNT; ++i) {
snprintf(path, 3, "/%d", i);
Write_test test(vfs_root, heap, path);
Write_test test(vfs_root, heap, path, env.ep());
count += test.wait();
}
elapsed_ms = timer.elapsed_ms() - elapsed_ms;
vfs_root.sync("/");
vfs_root_sync();
log("wrote ",count," bytes ",
count/elapsed_ms,"kB/s, ",
@ -593,13 +658,13 @@ void Component::construct(Genode::Env &env)
for (int i = 0; i < ROOT_TREE_COUNT; ++i) {
snprintf(path, 3, "/%d", i);
Read_test test(vfs_root, heap, path);
Read_test test(vfs_root, heap, path, env.ep());
count += test.wait();
}
elapsed_ms = timer.elapsed_ms() - elapsed_ms;
vfs_root.sync("/");
vfs_root_sync();
log("read ",count," bytes, ",
count/elapsed_ms,"kB/s, ",
@ -625,14 +690,14 @@ void Component::construct(Genode::Env &env)
for (int i = 0; i < ROOT_TREE_COUNT; ++i) {
snprintf(path, 3, "/%d", i);
Unlink_test test(vfs_root, heap, path);
Unlink_test test(vfs_root, heap, path, env.ep());
count += test.wait();
}
elapsed_ms = timer.elapsed_ms() - elapsed_ms;
vfs_root.sync("/");
vfs_root_sync();
log("unlinked ",count," files in ",elapsed_ms,"ms, ",
env.ram().used_ram().value/1024,"KiB consumed");