mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-22 06:57:51 +00:00
Notification support for the VFS library
Add a new 'Vfs_watch_handle' type to the VFS interface. This handle type will pass a handle context up through the I/O handler to the application when a notification event occurs. Watch support implemented for RAM and File_system plugins, all other file-systems return WATCH_ERR_STATIC by default. Test at run/fs_rom_update_ram and run/fs_rom_update_fs. Fix #1934
This commit is contained in:
parent
344d46ce78
commit
9c6b720ec1
@ -94,6 +94,47 @@ class Vfs::Dir_file_system : public File_system
|
||||
Dir_vfs_handle &operator = (Dir_vfs_handle const &);
|
||||
};
|
||||
|
||||
struct Dir_watch_handle : Vfs_watch_handle
|
||||
{
|
||||
struct Watch_handle_element;
|
||||
|
||||
typedef Genode::Registry<Watch_handle_element> Watch_handle_registry;
|
||||
|
||||
struct Watch_handle_element : Watch_handle_registry::Element
|
||||
{
|
||||
Vfs_watch_handle &watch_handle;
|
||||
Watch_handle_element(Watch_handle_registry ®istry,
|
||||
Vfs_watch_handle &handle)
|
||||
: Watch_handle_registry::Element(registry, *this),
|
||||
watch_handle(handle) { }
|
||||
};
|
||||
|
||||
Watch_handle_registry handle_registry { };
|
||||
|
||||
Dir_watch_handle(File_system &fs, Genode::Allocator &alloc)
|
||||
: Vfs_watch_handle(fs, alloc) { }
|
||||
|
||||
~Dir_watch_handle()
|
||||
{
|
||||
/* close all sub-handles */
|
||||
auto f = [&] (Watch_handle_element &e) {
|
||||
e.watch_handle.fs().close(&e.watch_handle);
|
||||
destroy(alloc(), &e);
|
||||
};
|
||||
handle_registry.for_each(f);
|
||||
}
|
||||
|
||||
/**
|
||||
* Propagate the handle context to each sub-handle
|
||||
*/
|
||||
void context(Context *ctx) override
|
||||
{
|
||||
handle_registry.for_each( [&] (Watch_handle_element &elem) {
|
||||
elem.watch_handle.context(ctx); } );
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/* pointer to first child file system */
|
||||
File_system *_first_file_system = nullptr;
|
||||
|
||||
@ -733,6 +774,41 @@ class Vfs::Dir_file_system : public File_system
|
||||
destroy(handle->alloc(), handle);
|
||||
}
|
||||
|
||||
Watch_result watch(char const *path,
|
||||
Vfs_watch_handle **handle,
|
||||
Allocator &alloc) override
|
||||
{
|
||||
/* static by default, no allocations */
|
||||
Watch_result r = WATCH_ERR_STATIC;
|
||||
Dir_watch_handle *meta_handle = nullptr;
|
||||
|
||||
for (File_system *fs = _first_file_system; fs; fs = fs->next) {
|
||||
Vfs_watch_handle *sub_handle;
|
||||
|
||||
if (fs->watch(path, &sub_handle, alloc) == WATCH_OK) {
|
||||
if (meta_handle == nullptr) {
|
||||
/* at least one non-static FS, allocate handle */
|
||||
meta_handle = new (alloc) Dir_watch_handle(*this, alloc);
|
||||
*handle = meta_handle;
|
||||
r = WATCH_OK;
|
||||
}
|
||||
|
||||
/* attach child FS handle to returned handle */
|
||||
new (alloc)
|
||||
Dir_watch_handle::Watch_handle_element(
|
||||
meta_handle->handle_registry, *sub_handle);
|
||||
}
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
void close(Vfs_watch_handle *handle) override
|
||||
{
|
||||
if (handle && (&handle->fs() == this))
|
||||
destroy(handle->alloc(), handle);
|
||||
}
|
||||
|
||||
Unlink_result unlink(char const *path) override
|
||||
{
|
||||
auto unlink_fn = [] (File_system &fs, char const *path)
|
||||
|
@ -18,6 +18,7 @@
|
||||
|
||||
namespace Vfs {
|
||||
class Vfs_handle;
|
||||
class Vfs_watch_handle;
|
||||
struct Directory_service;
|
||||
|
||||
using Genode::Allocator;
|
||||
@ -110,6 +111,32 @@ struct Vfs::Directory_service : Interface
|
||||
*/
|
||||
virtual void close(Vfs_handle *handle) = 0;
|
||||
|
||||
enum Watch_result
|
||||
{
|
||||
WATCH_ERR_UNACCESSIBLE,
|
||||
WATCH_ERR_STATIC,
|
||||
WATCH_ERR_OUT_OF_RAM,
|
||||
WATCH_ERR_OUT_OF_CAPS,
|
||||
WATCH_OK
|
||||
};
|
||||
|
||||
/**
|
||||
* Watch a file-system node for changes.
|
||||
*/
|
||||
virtual Watch_result watch(char const *path,
|
||||
Vfs_watch_handle**,
|
||||
Allocator&)
|
||||
{
|
||||
/* default implementation for static file-systems */
|
||||
Genode::warning("'", path, "' is static and cannot be watched");
|
||||
return WATCH_ERR_STATIC;
|
||||
}
|
||||
|
||||
virtual void close(Vfs_watch_handle *)
|
||||
{
|
||||
Genode::error("watch handle closed at invalid file-system");
|
||||
throw ~0;
|
||||
};
|
||||
|
||||
/**********
|
||||
** Stat **
|
||||
|
@ -27,7 +27,9 @@ namespace Vfs {
|
||||
|
||||
struct Vfs::Io_response_handler : Interface
|
||||
{
|
||||
virtual void handle_io_response(Vfs::Vfs_handle::Context *context) = 0;
|
||||
virtual void handle_io_response(Vfs_handle::Context *context) = 0;
|
||||
virtual void handle_watch_response(Vfs_watch_handle::Context*) {
|
||||
Genode::warning(__func__, " discarding event"); };
|
||||
};
|
||||
|
||||
|
||||
|
@ -19,6 +19,8 @@
|
||||
namespace Vfs{
|
||||
class Vfs_handle;
|
||||
class File_io_service;
|
||||
class File_system;
|
||||
class Vfs_watch_handle;
|
||||
}
|
||||
|
||||
|
||||
@ -109,4 +111,41 @@ class Vfs::Vfs_handle
|
||||
};
|
||||
|
||||
|
||||
class Vfs::Vfs_watch_handle
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Opaque handle context
|
||||
*/
|
||||
struct Context : List<Context>::Element { };
|
||||
|
||||
private:
|
||||
|
||||
File_system &_fs;
|
||||
Genode::Allocator &_alloc;
|
||||
Context *_context = nullptr;
|
||||
|
||||
/*
|
||||
* Noncopyable
|
||||
*/
|
||||
Vfs_watch_handle(Vfs_watch_handle const &);
|
||||
Vfs_watch_handle &operator = (Vfs_watch_handle const &);
|
||||
|
||||
public:
|
||||
|
||||
Vfs_watch_handle(File_system &fs,
|
||||
Genode::Allocator &alloc)
|
||||
:
|
||||
_fs(fs), _alloc(alloc)
|
||||
{ }
|
||||
|
||||
virtual ~Vfs_watch_handle() { }
|
||||
|
||||
File_system &fs() { return _fs; }
|
||||
Allocator &alloc() { return _alloc; }
|
||||
virtual void context(Context *context) { _context = context; }
|
||||
Context *context() const { return _context; }
|
||||
};
|
||||
|
||||
#endif /* _INCLUDE__VFS__VFS_HANDLE_H_ */
|
||||
|
138
repos/os/run/fs_rom_update_fs.run
Normal file
138
repos/os/run/fs_rom_update_fs.run
Normal file
@ -0,0 +1,138 @@
|
||||
#
|
||||
# Build
|
||||
#
|
||||
set build_components {
|
||||
core init
|
||||
app/rom_logger
|
||||
app/rom_to_file
|
||||
drivers/timer
|
||||
server/dynamic_rom
|
||||
server/fs_rom
|
||||
server/vfs
|
||||
}
|
||||
|
||||
build $build_components
|
||||
|
||||
create_boot_directory
|
||||
|
||||
#
|
||||
# Generate config
|
||||
#
|
||||
append config {
|
||||
<config>
|
||||
<parent-provides>
|
||||
<service name="CPU"/>
|
||||
<service name="IO_MEM"/>
|
||||
<service name="IO_PORT"/>
|
||||
<service name="IRQ"/>
|
||||
<service name="LOG"/>
|
||||
<service name="PD"/>
|
||||
<service name="RM"/>
|
||||
<service name="ROM"/>
|
||||
</parent-provides>
|
||||
<default-route>
|
||||
<any-service> <parent/> <any-child/> </any-service>
|
||||
</default-route>
|
||||
<default caps="100"/>
|
||||
<start name="timer">
|
||||
<resource name="RAM" quantum="1M"/>
|
||||
<provides><service name="Timer"/></provides>
|
||||
</start>
|
||||
<start name="vfs_1">
|
||||
<binary name="vfs"/>
|
||||
<resource name="RAM" quantum="10M"/>
|
||||
<provides><service name="File_system"/></provides>
|
||||
<config>
|
||||
<vfs> <ram/> </vfs>
|
||||
<policy label_prefix="rom_to_file" root="/" writeable="yes"/>
|
||||
<policy label_prefix="vfs_2" root="/" writeable="no"/>
|
||||
</config>
|
||||
</start>
|
||||
<start name="vfs_2">
|
||||
<binary name="vfs"/>
|
||||
<resource name="RAM" quantum="10M"/>
|
||||
<provides><service name="File_system"/></provides>
|
||||
<config>
|
||||
<vfs> <fs/> </vfs>
|
||||
<policy label_prefix="fs_rom" root="/" writeable="no"/>
|
||||
</config>
|
||||
<route>
|
||||
<service name="File_system">
|
||||
<child name="vfs_1"/> </service>
|
||||
<any-service> <parent/> <any-child/> </any-service>
|
||||
</route>
|
||||
</start>
|
||||
<start name="dynamic_rom">
|
||||
<resource name="RAM" quantum="4M"/>
|
||||
<provides><service name="ROM"/></provides>
|
||||
<config verbose="yes">
|
||||
<rom name="dynamic_rom">
|
||||
<inline description="iteration 1">
|
||||
<config iteration="1" />
|
||||
</inline>
|
||||
<sleep milliseconds="2000" />
|
||||
<inline description="iteration 2">
|
||||
<config iteration="2" />
|
||||
</inline>
|
||||
<sleep milliseconds="2000" />
|
||||
<inline description="iteration 3">
|
||||
<config iteration="3" />
|
||||
</inline>
|
||||
<sleep milliseconds="2000" />
|
||||
<inline description="iteration 4">
|
||||
<config iteration="4" />
|
||||
</inline>
|
||||
<sleep milliseconds="2000" />
|
||||
</rom>
|
||||
</config>
|
||||
</start>
|
||||
<start name="rom_to_file">
|
||||
<resource name="RAM" quantum="2M"/>
|
||||
<config rom="dynamic_rom"/>
|
||||
<route>
|
||||
<service name="ROM" label="dynamic_rom"> <child name="dynamic_rom"/> </service>
|
||||
<service name="File_system" > <child name="vfs_1"/> </service>
|
||||
<any-service> <parent/> <any-child/> </any-service>
|
||||
</route>
|
||||
</start>
|
||||
|
||||
<start name="fs_rom">
|
||||
<resource name="RAM" quantum="2M"/>
|
||||
<provides><service name="ROM"/></provides>
|
||||
<route>
|
||||
<service name="File_system" > <child name="vfs_2"/> </service>
|
||||
<any-service> <parent/> </any-service>
|
||||
</route>
|
||||
</start>
|
||||
<start name="rom_logger">
|
||||
<resource name="RAM" quantum="1M"/>
|
||||
<config rom="dynamic_rom"/>
|
||||
<route>
|
||||
<service name="ROM" label="dynamic_rom"> <child name="fs_rom"/> </service>
|
||||
<any-service> <parent/> </any-service>
|
||||
</route>
|
||||
</start>
|
||||
</config>}
|
||||
|
||||
install_config $config
|
||||
|
||||
#
|
||||
# Boot modules
|
||||
#
|
||||
|
||||
# generic modules
|
||||
set boot_modules {
|
||||
core ld.lib.so init
|
||||
dynamic_rom
|
||||
fs_rom
|
||||
vfs
|
||||
rom_logger
|
||||
rom_to_file
|
||||
timer
|
||||
}
|
||||
|
||||
build_boot_image $boot_modules
|
||||
|
||||
append qemu_args " -nographic"
|
||||
|
||||
run_genode_until {.*<config iteration="4" />.*} 60
|
123
repos/os/run/fs_rom_update_ram.run
Normal file
123
repos/os/run/fs_rom_update_ram.run
Normal file
@ -0,0 +1,123 @@
|
||||
#
|
||||
# Build
|
||||
#
|
||||
set build_components {
|
||||
core init
|
||||
app/rom_logger
|
||||
app/rom_to_file
|
||||
drivers/timer
|
||||
server/dynamic_rom
|
||||
server/fs_rom
|
||||
server/vfs
|
||||
}
|
||||
|
||||
build $build_components
|
||||
|
||||
create_boot_directory
|
||||
|
||||
#
|
||||
# Generate config
|
||||
#
|
||||
append config {
|
||||
<config>
|
||||
<parent-provides>
|
||||
<service name="CPU"/>
|
||||
<service name="IO_MEM"/>
|
||||
<service name="IO_PORT"/>
|
||||
<service name="IRQ"/>
|
||||
<service name="LOG"/>
|
||||
<service name="PD"/>
|
||||
<service name="RM"/>
|
||||
<service name="ROM"/>
|
||||
</parent-provides>
|
||||
<default-route>
|
||||
<any-service> <parent/> <any-child/> </any-service>
|
||||
</default-route>
|
||||
<default caps="100"/>
|
||||
<start name="timer">
|
||||
<resource name="RAM" quantum="1M"/>
|
||||
<provides><service name="Timer"/></provides>
|
||||
</start>
|
||||
<start name="vfs">
|
||||
<resource name="RAM" quantum="10M"/>
|
||||
<provides><service name="File_system"/></provides>
|
||||
<config>
|
||||
<vfs> <ram/> </vfs>
|
||||
<policy label_prefix="rom_to_file" root="/" writeable="yes"/>
|
||||
<policy label_prefix="fs_rom" root="/" writeable="no"/>
|
||||
</config>
|
||||
</start>
|
||||
<start name="dynamic_rom">
|
||||
<resource name="RAM" quantum="4M"/>
|
||||
<provides><service name="ROM"/></provides>
|
||||
<config verbose="yes">
|
||||
<rom name="dynamic_rom">
|
||||
<inline description="iteration 1">
|
||||
<config iteration="1" />
|
||||
</inline>
|
||||
<sleep milliseconds="2000" />
|
||||
<inline description="iteration 2">
|
||||
<config iteration="2" />
|
||||
</inline>
|
||||
<sleep milliseconds="2000" />
|
||||
<inline description="iteration 3">
|
||||
<config iteration="3" />
|
||||
</inline>
|
||||
<sleep milliseconds="2000" />
|
||||
<inline description="iteration 4">
|
||||
<config iteration="4" />
|
||||
</inline>
|
||||
<sleep milliseconds="2000" />
|
||||
</rom>
|
||||
</config>
|
||||
</start>
|
||||
<start name="rom_to_file">
|
||||
<resource name="RAM" quantum="2M"/>
|
||||
<config rom="dynamic_rom"/>
|
||||
<route>
|
||||
<service name="ROM" label="dynamic_rom"> <child name="dynamic_rom"/> </service>
|
||||
<service name="File_system" > <child name="vfs"/> </service>
|
||||
<any-service> <parent/> <any-child/> </any-service>
|
||||
</route>
|
||||
</start>
|
||||
|
||||
<start name="fs_rom">
|
||||
<resource name="RAM" quantum="2M"/>
|
||||
<provides><service name="ROM"/></provides>
|
||||
<route>
|
||||
<service name="File_system" > <child name="vfs"/> </service>
|
||||
<any-service> <parent/> </any-service>
|
||||
</route>
|
||||
</start>
|
||||
<start name="rom_logger">
|
||||
<resource name="RAM" quantum="1M"/>
|
||||
<config rom="dynamic_rom"/>
|
||||
<route>
|
||||
<service name="ROM" label="dynamic_rom"> <child name="fs_rom"/> </service>
|
||||
<any-service> <parent/> </any-service>
|
||||
</route>
|
||||
</start>
|
||||
</config>}
|
||||
|
||||
install_config $config
|
||||
|
||||
#
|
||||
# Boot modules
|
||||
#
|
||||
|
||||
# generic modules
|
||||
set boot_modules {
|
||||
core ld.lib.so init
|
||||
dynamic_rom
|
||||
fs_rom
|
||||
vfs
|
||||
rom_logger
|
||||
rom_to_file
|
||||
timer
|
||||
}
|
||||
|
||||
build_boot_image $boot_modules
|
||||
|
||||
append qemu_args " -nographic"
|
||||
|
||||
run_genode_until {.*<config iteration="4" />.*} 60
|
@ -29,7 +29,6 @@ class Vfs::Fs_file_system : public File_system
|
||||
{
|
||||
private:
|
||||
|
||||
|
||||
/*
|
||||
* Lock used to serialize the interaction with the packet stream of the
|
||||
* file-system session.
|
||||
@ -41,7 +40,7 @@ class Vfs::Fs_file_system : public File_system
|
||||
|
||||
Genode::Env &_env;
|
||||
Genode::Allocator_avl _fs_packet_alloc;
|
||||
Io_response_handler &_io_handler;
|
||||
Io_response_handler &_event_handler;
|
||||
|
||||
typedef Genode::String<64> Label_string;
|
||||
Label_string _label;
|
||||
@ -54,6 +53,7 @@ class Vfs::Fs_file_system : public File_system
|
||||
typedef Genode::Id_space<::File_system::Node> Handle_space;
|
||||
|
||||
Handle_space _handle_space { };
|
||||
Handle_space _watch_handle_space { };
|
||||
|
||||
struct Handle_state
|
||||
{
|
||||
@ -82,7 +82,7 @@ class Vfs::Fs_file_system : public File_system
|
||||
friend class Genode::Id_space<::File_system::Node>;
|
||||
|
||||
::File_system::Connection &_fs;
|
||||
Io_response_handler &_io_handler;
|
||||
Io_response_handler &_event_handler;
|
||||
|
||||
bool _queue_read(file_size count, file_size const seek_offset)
|
||||
{
|
||||
@ -145,7 +145,7 @@ class Vfs::Fs_file_system : public File_system
|
||||
* Notify anyone who might have failed on
|
||||
* 'alloc_packet()' or 'submit_packet()'
|
||||
*/
|
||||
_io_handler.handle_io_response(nullptr);
|
||||
_event_handler.handle_io_response(nullptr);
|
||||
|
||||
return READ_OK;
|
||||
}
|
||||
@ -158,7 +158,7 @@ class Vfs::Fs_file_system : public File_system
|
||||
:
|
||||
Vfs_handle(fs, fs, alloc, status_flags),
|
||||
Handle_space::Element(*this, space, node_handle),
|
||||
_fs(fs_connection), _io_handler(io_handler)
|
||||
_fs(fs_connection), _event_handler(io_handler)
|
||||
{ }
|
||||
|
||||
::File_system::File_handle file_handle() const
|
||||
@ -227,7 +227,7 @@ class Vfs::Fs_file_system : public File_system
|
||||
* Notify anyone who might have failed on
|
||||
* 'alloc_packet()' or 'submit_packet()'
|
||||
*/
|
||||
_io_handler.handle_io_response(nullptr);
|
||||
_event_handler.handle_io_response(nullptr);
|
||||
|
||||
return SYNC_OK;
|
||||
}
|
||||
@ -355,19 +355,40 @@ class Vfs::Fs_file_system : public File_system
|
||||
}
|
||||
};
|
||||
|
||||
struct Fs_vfs_watch_handle : Vfs_watch_handle,
|
||||
private ::File_system::Node,
|
||||
private Handle_space::Element
|
||||
{
|
||||
friend class Genode::Id_space<::File_system::Node>;
|
||||
|
||||
::File_system::Watch_handle const fs_handle;
|
||||
|
||||
Fs_vfs_watch_handle(Vfs::File_system &fs,
|
||||
Allocator &alloc,
|
||||
Handle_space &space,
|
||||
::File_system::Watch_handle handle)
|
||||
:
|
||||
Vfs_watch_handle(fs, alloc),
|
||||
Handle_space::Element(*this, space, handle),
|
||||
fs_handle(handle)
|
||||
{ }
|
||||
};
|
||||
|
||||
struct Post_signal_hook : Genode::Entrypoint::Post_signal_hook
|
||||
{
|
||||
Genode::Entrypoint &_ep;
|
||||
Io_response_handler &_io_handler;
|
||||
Io_response_handler &_event_handler;
|
||||
List<Vfs_handle::Context> _context_list { };
|
||||
List<Vfs_watch_handle::Context>
|
||||
_watch_context_list { };
|
||||
Lock _list_lock { };
|
||||
bool _notify_all { false };
|
||||
|
||||
Post_signal_hook(Genode::Entrypoint &ep,
|
||||
Io_response_handler &io_handler)
|
||||
: _ep(ep), _io_handler(io_handler) { }
|
||||
: _ep(ep), _event_handler(io_handler) { }
|
||||
|
||||
void arm(Vfs_handle::Context *context)
|
||||
void arm_io_event(Vfs_handle::Context *context)
|
||||
{
|
||||
if (!context) {
|
||||
Lock::Guard list_guard(_list_lock);
|
||||
@ -391,6 +412,27 @@ class Vfs::Fs_file_system : public File_system
|
||||
_ep.schedule_post_signal_hook(this);
|
||||
}
|
||||
|
||||
void arm_watch_event(Vfs_watch_handle::Context &context)
|
||||
{
|
||||
{
|
||||
Lock::Guard list_guard(_list_lock);
|
||||
|
||||
for (Vfs_watch_handle::Context *list_context = _watch_context_list.first();
|
||||
list_context;
|
||||
list_context = list_context->next())
|
||||
{
|
||||
if (list_context == &context) {
|
||||
/* already in list */
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
_watch_context_list.insert(&context);
|
||||
}
|
||||
|
||||
_ep.schedule_post_signal_hook(this);
|
||||
}
|
||||
|
||||
void function() override
|
||||
{
|
||||
Vfs_handle::Context *context = nullptr;
|
||||
@ -411,14 +453,26 @@ class Vfs::Fs_file_system : public File_system
|
||||
}
|
||||
|
||||
if (context || notify_all)
|
||||
_io_handler.handle_io_response(context);
|
||||
_event_handler.handle_io_response(context);
|
||||
|
||||
/* done if no contexts and all notified */
|
||||
} while (context);
|
||||
|
||||
for (;;) {
|
||||
Vfs_watch_handle::Context *context = nullptr;
|
||||
{
|
||||
Lock::Guard list_guard(_list_lock);
|
||||
|
||||
context = _watch_context_list.first();
|
||||
if (!context) break;
|
||||
_watch_context_list.remove(context);
|
||||
_event_handler.handle_watch_response(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Post_signal_hook _post_signal_hook { _env.ep(), _io_handler };
|
||||
Post_signal_hook _post_signal_hook { _env.ep(), _event_handler };
|
||||
|
||||
file_size _read(Fs_vfs_handle &handle, void *buf,
|
||||
file_size const count, file_size const seek_offset)
|
||||
@ -504,7 +558,7 @@ class Vfs::Fs_file_system : public File_system
|
||||
void _ready_to_submit()
|
||||
{
|
||||
/* notify anyone who might have failed on write() ready_to_submit */
|
||||
_post_signal_hook.arm(nullptr);
|
||||
_post_signal_hook.arm_io_event(nullptr);
|
||||
}
|
||||
|
||||
void _handle_ack()
|
||||
@ -519,7 +573,13 @@ class Vfs::Fs_file_system : public File_system
|
||||
Handle_space::Id const id(packet.handle());
|
||||
|
||||
try {
|
||||
_handle_space.apply<Fs_vfs_handle>(id, [&] (Fs_vfs_handle &handle)
|
||||
if (packet.operation() == Packet_descriptor::CONTENT_CHANGED) {
|
||||
_watch_handle_space.apply<Fs_vfs_watch_handle>(id, [&] (Fs_vfs_watch_handle &handle) {
|
||||
|
||||
if (auto *ctx = handle.context())
|
||||
_post_signal_hook.arm_watch_event(*ctx);
|
||||
});
|
||||
} else _handle_space.apply<Fs_vfs_handle>(id, [&] (Fs_vfs_handle &handle)
|
||||
{
|
||||
if (!packet.succeeded())
|
||||
Genode::error("packet operation=", (int)packet.operation(), " failed");
|
||||
@ -527,13 +587,13 @@ class Vfs::Fs_file_system : public File_system
|
||||
switch (packet.operation()) {
|
||||
case Packet_descriptor::READ_READY:
|
||||
handle.read_ready_state = Handle_state::Read_ready_state::READY;
|
||||
_post_signal_hook.arm(handle.context);
|
||||
_post_signal_hook.arm_io_event(handle.context);
|
||||
break;
|
||||
|
||||
case Packet_descriptor::READ:
|
||||
handle.queued_read_packet = packet;
|
||||
handle.queued_read_state = Handle_state::Queued_state::ACK;
|
||||
_post_signal_hook.arm(handle.context);
|
||||
_post_signal_hook.arm_io_event(handle.context);
|
||||
break;
|
||||
|
||||
case Packet_descriptor::WRITE:
|
||||
@ -541,18 +601,18 @@ class Vfs::Fs_file_system : public File_system
|
||||
* Notify anyone who might have failed on
|
||||
* 'alloc_packet()'
|
||||
*/
|
||||
_post_signal_hook.arm(nullptr);
|
||||
_post_signal_hook.arm_io_event(nullptr);
|
||||
|
||||
break;
|
||||
|
||||
case Packet_descriptor::CONTENT_CHANGED:
|
||||
_post_signal_hook.arm(handle.context);
|
||||
break;
|
||||
|
||||
case Packet_descriptor::SYNC:
|
||||
handle.queued_sync_packet = packet;
|
||||
handle.queued_sync_state = Handle_state::Queued_state::ACK;
|
||||
_post_signal_hook.arm(handle.context);
|
||||
_post_signal_hook.arm_io_event(handle.context);
|
||||
break;
|
||||
|
||||
case Packet_descriptor::CONTENT_CHANGED:
|
||||
/* previously handled */
|
||||
break;
|
||||
}
|
||||
});
|
||||
@ -577,12 +637,12 @@ class Vfs::Fs_file_system : public File_system
|
||||
Fs_file_system(Genode::Env &env,
|
||||
Genode::Allocator &alloc,
|
||||
Genode::Xml_node config,
|
||||
Io_response_handler &io_handler,
|
||||
Io_response_handler &event_handler,
|
||||
File_system &)
|
||||
:
|
||||
_env(env),
|
||||
_fs_packet_alloc(&alloc),
|
||||
_io_handler(io_handler),
|
||||
_event_handler(event_handler),
|
||||
_label(config.attribute_value("label", Label_string())),
|
||||
_root( config.attribute_value("root", Root_string())),
|
||||
_fs(env, _fs_packet_alloc,
|
||||
@ -613,7 +673,7 @@ class Vfs::Fs_file_system : public File_system
|
||||
try {
|
||||
::File_system::Node_handle node = _fs.node(path);
|
||||
Fs_handle_guard node_guard(*this, _fs, node, _handle_space,
|
||||
_fs, _io_handler);
|
||||
_fs, _event_handler);
|
||||
status = _fs.status(node);
|
||||
}
|
||||
catch (::File_system::Lookup_failed) { return STAT_ERR_NO_ENTRY; }
|
||||
@ -649,7 +709,7 @@ class Vfs::Fs_file_system : public File_system
|
||||
try {
|
||||
::File_system::Dir_handle dir = _fs.dir(dir_path.base(), false);
|
||||
Fs_handle_guard dir_guard(*this, _fs, dir, _handle_space, _fs,
|
||||
_io_handler);
|
||||
_event_handler);
|
||||
|
||||
_fs.unlink(dir, file_name.base() + 1);
|
||||
}
|
||||
@ -685,12 +745,12 @@ class Vfs::Fs_file_system : public File_system
|
||||
_fs.dir(from_dir_path.base(), false);
|
||||
|
||||
Fs_handle_guard from_dir_guard(*this, _fs, from_dir,
|
||||
_handle_space, _fs, _io_handler);
|
||||
_handle_space, _fs, _event_handler);
|
||||
|
||||
::File_system::Dir_handle to_dir = _fs.dir(to_dir_path.base(),
|
||||
false);
|
||||
Fs_handle_guard to_dir_guard(*this, _fs, to_dir, _handle_space,
|
||||
_fs, _io_handler);
|
||||
_fs, _event_handler);
|
||||
|
||||
_fs.move(from_dir, from_file_name.base() + 1,
|
||||
to_dir, to_file_name.base() + 1);
|
||||
@ -709,7 +769,7 @@ class Vfs::Fs_file_system : public File_system
|
||||
::File_system::Node_handle node;
|
||||
try { node = _fs.node(path); } catch (...) { return 0; }
|
||||
Fs_handle_guard node_guard(*this, _fs, node, _handle_space, _fs,
|
||||
_io_handler);
|
||||
_event_handler);
|
||||
|
||||
::File_system::Status status = _fs.status(node);
|
||||
|
||||
@ -721,7 +781,7 @@ class Vfs::Fs_file_system : public File_system
|
||||
try {
|
||||
::File_system::Node_handle node = _fs.node(path);
|
||||
Fs_handle_guard node_guard(*this, _fs, node, _handle_space,
|
||||
_fs, _io_handler);
|
||||
_fs, _event_handler);
|
||||
|
||||
::File_system::Status status = _fs.status(node);
|
||||
|
||||
@ -767,7 +827,7 @@ class Vfs::Fs_file_system : public File_system
|
||||
try {
|
||||
::File_system::Dir_handle dir = _fs.dir(dir_path.base(), false);
|
||||
Fs_handle_guard dir_guard(*this, _fs, dir, _handle_space, _fs,
|
||||
_io_handler);
|
||||
_event_handler);
|
||||
|
||||
::File_system::File_handle file = _fs.file(dir,
|
||||
file_name.base() + 1,
|
||||
@ -775,7 +835,7 @@ class Vfs::Fs_file_system : public File_system
|
||||
|
||||
*out_handle = new (alloc)
|
||||
Fs_vfs_file_handle(*this, alloc, vfs_mode, _handle_space,
|
||||
file, _fs, _io_handler);
|
||||
file, _fs, _event_handler);
|
||||
}
|
||||
catch (::File_system::Lookup_failed) { return OPEN_ERR_UNACCESSIBLE; }
|
||||
catch (::File_system::Permission_denied) { return OPEN_ERR_NO_PERM; }
|
||||
@ -803,7 +863,7 @@ class Vfs::Fs_file_system : public File_system
|
||||
|
||||
*out_handle = new (alloc)
|
||||
Fs_vfs_dir_handle(*this, alloc, ::File_system::READ_ONLY,
|
||||
_handle_space, dir, _fs, _io_handler);
|
||||
_handle_space, dir, _fs, _event_handler);
|
||||
}
|
||||
catch (::File_system::Lookup_failed) { return OPENDIR_ERR_LOOKUP_FAILED; }
|
||||
catch (::File_system::Name_too_long) { return OPENDIR_ERR_NAME_TOO_LONG; }
|
||||
@ -835,7 +895,7 @@ class Vfs::Fs_file_system : public File_system
|
||||
false);
|
||||
|
||||
Fs_handle_guard from_dir_guard(*this, _fs, dir_handle,
|
||||
_handle_space, _fs, _io_handler);
|
||||
_handle_space, _fs, _event_handler);
|
||||
|
||||
::File_system::Symlink_handle symlink_handle =
|
||||
_fs.symlink(dir_handle, symlink_name.base() + 1, create);
|
||||
@ -844,7 +904,7 @@ class Vfs::Fs_file_system : public File_system
|
||||
Fs_vfs_symlink_handle(*this, alloc,
|
||||
::File_system::READ_ONLY,
|
||||
_handle_space, symlink_handle, _fs,
|
||||
_io_handler);
|
||||
_event_handler);
|
||||
|
||||
return OPENLINK_OK;
|
||||
}
|
||||
@ -871,6 +931,41 @@ class Vfs::Fs_file_system : public File_system
|
||||
destroy(fs_handle->alloc(), fs_handle);
|
||||
}
|
||||
|
||||
Watch_result watch(char const *path,
|
||||
Vfs_watch_handle **handle,
|
||||
Allocator &alloc)
|
||||
{
|
||||
using namespace ::File_system;
|
||||
|
||||
Watch_result res = WATCH_ERR_UNACCESSIBLE;
|
||||
::File_system::Watch_handle fs_handle { -1U };
|
||||
|
||||
try { fs_handle = _fs.watch(path); }
|
||||
catch (Lookup_failed) { return WATCH_ERR_UNACCESSIBLE; }
|
||||
catch (Permission_denied) { return WATCH_ERR_STATIC; }
|
||||
catch (Out_of_ram) { return WATCH_ERR_OUT_OF_RAM; }
|
||||
catch (Out_of_caps) { return WATCH_ERR_OUT_OF_CAPS; }
|
||||
|
||||
try {
|
||||
*handle = new (alloc)
|
||||
Fs_vfs_watch_handle(
|
||||
*this, alloc, _watch_handle_space, fs_handle);
|
||||
return WATCH_OK;
|
||||
}
|
||||
catch (Out_of_ram) { res = WATCH_ERR_OUT_OF_RAM; }
|
||||
catch (Out_of_caps) { res = WATCH_ERR_OUT_OF_CAPS; }
|
||||
_fs.close(fs_handle);
|
||||
return res;
|
||||
}
|
||||
|
||||
void close(Vfs_watch_handle *vfs_handle) override
|
||||
{
|
||||
Fs_vfs_watch_handle *handle =
|
||||
static_cast<Fs_vfs_watch_handle *>(vfs_handle);
|
||||
_fs.close(handle->fs_handle);
|
||||
destroy(handle->alloc(), handle);
|
||||
};
|
||||
|
||||
|
||||
/***************************
|
||||
** File_system interface **
|
||||
|
@ -19,11 +19,16 @@
|
||||
#include <dataspace/client.h>
|
||||
#include <util/avl_tree.h>
|
||||
|
||||
namespace Vfs { class Ram_file_system; }
|
||||
|
||||
namespace Vfs_ram {
|
||||
|
||||
using namespace Genode;
|
||||
using namespace Vfs;
|
||||
|
||||
struct Io_handle;
|
||||
struct Watch_handle;
|
||||
|
||||
class Node;
|
||||
class File;
|
||||
class Symlink;
|
||||
@ -49,7 +54,39 @@ namespace Vfs_ram {
|
||||
|
||||
}
|
||||
|
||||
namespace Vfs { class Ram_file_system; }
|
||||
|
||||
struct Vfs_ram::Io_handle final : public Vfs_handle,
|
||||
private Genode::List<Io_handle>::Element
|
||||
{
|
||||
friend Genode::List<Io_handle>;
|
||||
|
||||
Vfs_ram::Node &node;
|
||||
|
||||
/* Track if this handle has modified its node */
|
||||
bool modifying = false;
|
||||
|
||||
Io_handle(Vfs::File_system &fs,
|
||||
Allocator &alloc,
|
||||
int status_flags,
|
||||
Vfs_ram::Node &node)
|
||||
: Vfs_handle(fs, fs, alloc, status_flags), node(node)
|
||||
{ }
|
||||
};
|
||||
|
||||
|
||||
struct Vfs_ram::Watch_handle final : public Vfs_watch_handle,
|
||||
private Genode::List<Watch_handle>::Element
|
||||
{
|
||||
friend Genode::List<Watch_handle>;
|
||||
using Genode::List<Watch_handle>::Element::next;
|
||||
|
||||
Vfs_ram::Node &node;
|
||||
|
||||
Watch_handle(Vfs::File_system &fs,
|
||||
Allocator &alloc,
|
||||
Node &node)
|
||||
: Vfs_watch_handle(fs, alloc), node(node) { }
|
||||
};
|
||||
|
||||
|
||||
class Vfs_ram::Node : private Genode::Avl_node<Node>, private Genode::Lock
|
||||
@ -58,10 +95,16 @@ class Vfs_ram::Node : private Genode::Avl_node<Node>, private Genode::Lock
|
||||
|
||||
friend class Genode::Avl_node<Node>;
|
||||
friend class Genode::Avl_tree<Node>;
|
||||
friend class Genode::List<Io_handle>;
|
||||
friend class Genode::List<Io_handle>::Element;
|
||||
friend class Genode::List<Watch_handle>;
|
||||
friend class Genode::List<Watch_handle>::Element;
|
||||
friend class Watch_handle;
|
||||
friend class Directory;
|
||||
|
||||
char _name[MAX_NAME_LEN];
|
||||
int _open_handles = 0;
|
||||
Genode::List<Io_handle> _io_handles { };
|
||||
Genode::List<Watch_handle> _watch_handles { };
|
||||
|
||||
/**
|
||||
* Generate unique inode number
|
||||
@ -89,37 +132,45 @@ class Vfs_ram::Node : private Genode::Avl_node<Node>, private Genode::Lock
|
||||
|
||||
virtual Vfs::file_size length() = 0;
|
||||
|
||||
/**
|
||||
* Increment reference counter
|
||||
*/
|
||||
void open() { ++_open_handles; }
|
||||
void open(Io_handle &handle) { _io_handles.insert(&handle); }
|
||||
void open(Watch_handle &handle) { _watch_handles.insert(&handle); }
|
||||
|
||||
bool close_but_keep()
|
||||
bool opened() const
|
||||
{
|
||||
if (--_open_handles < 0) {
|
||||
inode = 0;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
return _io_handles.first() != nullptr;
|
||||
}
|
||||
|
||||
virtual size_t read(char * /* dst */, size_t /* len */, file_size /* seek_offset */)
|
||||
void close(Io_handle &handle) { _io_handles.remove(&handle); }
|
||||
void close(Watch_handle &handle) { _watch_handles.remove(&handle); }
|
||||
|
||||
void notify(Io_response_handler &handler)
|
||||
{
|
||||
for (Watch_handle *h = _watch_handles.first(); h; h = h->next()) {
|
||||
if (auto *ctx = h->context()) {
|
||||
handler.handle_watch_response(ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void unlink() { inode = 0; }
|
||||
bool unlinked() const { return inode == 0; }
|
||||
|
||||
virtual size_t read(char*, size_t, file_size)
|
||||
{
|
||||
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 */)
|
||||
virtual Vfs::File_io_service::Read_result complete_read(char *,
|
||||
file_size,
|
||||
file_size,
|
||||
file_size &)
|
||||
{
|
||||
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 */)
|
||||
virtual size_t write(char const *, size_t, file_size)
|
||||
{
|
||||
Genode::error("Vfs_ram::Node::write() called");
|
||||
return 0;
|
||||
@ -308,8 +359,8 @@ class Vfs_ram::Symlink : public Vfs_ram::Node
|
||||
|
||||
Vfs::File_io_service::Read_result complete_read(char *dst,
|
||||
file_size count,
|
||||
file_size /* seek_offset */,
|
||||
file_size &out_count) override
|
||||
file_size,
|
||||
file_size &out_count) override
|
||||
{
|
||||
out_count = get(dst, count);
|
||||
return Vfs::File_io_service::READ_OK;
|
||||
@ -344,7 +395,7 @@ class Vfs_ram::Directory : public Vfs_ram::Node
|
||||
while (Node *node = _entries.first()) {
|
||||
_entries.remove(node);
|
||||
if (File *file = dynamic_cast<File*>(node)) {
|
||||
if (file->close_but_keep())
|
||||
if (file->opened())
|
||||
continue;
|
||||
} else if (Directory *dir = dynamic_cast<Directory*>(node)) {
|
||||
dir->empty(alloc);
|
||||
@ -426,23 +477,12 @@ class Vfs::Ram_file_system : public Vfs::File_system
|
||||
{
|
||||
private:
|
||||
|
||||
struct Ram_vfs_handle : Vfs_handle
|
||||
{
|
||||
Vfs_ram::Node &node;
|
||||
friend class Genode::List<Vfs_ram::Watch_handle>;
|
||||
|
||||
Ram_vfs_handle(Ram_file_system &fs,
|
||||
Allocator &alloc,
|
||||
int status_flags,
|
||||
Vfs_ram::Node &node)
|
||||
: Vfs_handle(fs, fs, alloc, status_flags), node(node)
|
||||
{
|
||||
node.open();
|
||||
}
|
||||
};
|
||||
|
||||
Genode::Env &_env;
|
||||
Genode::Allocator &_alloc;
|
||||
Vfs_ram::Directory _root = { "" };
|
||||
Genode::Env &_env;
|
||||
Genode::Allocator &_alloc;
|
||||
Io_response_handler &_io_handler;
|
||||
Vfs_ram::Directory _root = { "" };
|
||||
|
||||
Vfs_ram::Node *lookup(char const *path, bool return_parent = false)
|
||||
{
|
||||
@ -493,8 +533,10 @@ class Vfs::Ram_file_system : public Vfs::File_system
|
||||
using namespace Vfs_ram;
|
||||
|
||||
if (File *file = dynamic_cast<File*>(node)) {
|
||||
if (file->close_but_keep())
|
||||
if (file->opened()) {
|
||||
file->unlink();
|
||||
return;
|
||||
}
|
||||
} else if (Directory *dir = dynamic_cast<Directory*>(node)) {
|
||||
dir->empty(_alloc);
|
||||
}
|
||||
@ -507,8 +549,9 @@ class Vfs::Ram_file_system : public Vfs::File_system
|
||||
Ram_file_system(Genode::Env &env,
|
||||
Genode::Allocator &alloc,
|
||||
Genode::Xml_node,
|
||||
Io_response_handler &, File_system &)
|
||||
: _env(env), _alloc(alloc) { }
|
||||
Io_response_handler &io_handler,
|
||||
File_system &)
|
||||
: _env(env), _alloc(alloc), _io_handler(io_handler) { }
|
||||
|
||||
~Ram_file_system() { _root.empty(_alloc); }
|
||||
|
||||
@ -566,6 +609,7 @@ class Vfs::Ram_file_system : public Vfs::File_system
|
||||
try { file = new (_alloc) File(name, _alloc); }
|
||||
catch (Out_of_memory) { return OPEN_ERR_NO_SPACE; }
|
||||
parent->adopt(file);
|
||||
parent->notify(_io_handler);
|
||||
} else {
|
||||
Node *node = lookup(path);
|
||||
if (!node) return OPEN_ERR_UNACCESSIBLE;
|
||||
@ -575,7 +619,7 @@ class Vfs::Ram_file_system : public Vfs::File_system
|
||||
}
|
||||
|
||||
try {
|
||||
*handle = new (alloc) Ram_vfs_handle(*this, alloc, mode, *file);
|
||||
*handle = new (alloc) Io_handle(*this, alloc, mode, *file);
|
||||
return OPEN_OK;
|
||||
} catch (Genode::Out_of_ram) {
|
||||
if (create) {
|
||||
@ -607,6 +651,8 @@ class Vfs::Ram_file_system : public Vfs::File_system
|
||||
Directory *dir;
|
||||
|
||||
if (create) {
|
||||
if (*name == '\0')
|
||||
return OPENDIR_ERR_NODE_ALREADY_EXISTS;
|
||||
|
||||
if (strlen(name) >= MAX_NAME_LEN)
|
||||
return OPENDIR_ERR_NAME_TOO_LONG;
|
||||
@ -618,7 +664,7 @@ class Vfs::Ram_file_system : public Vfs::File_system
|
||||
catch (Out_of_memory) { return OPENDIR_ERR_NO_SPACE; }
|
||||
|
||||
parent->adopt(dir);
|
||||
|
||||
parent->notify(_io_handler);
|
||||
} else {
|
||||
|
||||
Node *node = lookup(path);
|
||||
@ -629,9 +675,8 @@ class Vfs::Ram_file_system : public Vfs::File_system
|
||||
}
|
||||
|
||||
try {
|
||||
*handle = new (alloc) Ram_vfs_handle(*this, alloc,
|
||||
Ram_vfs_handle::STATUS_RDONLY,
|
||||
*dir);
|
||||
*handle = new (alloc) Io_handle(
|
||||
*this, alloc, Io_handle::STATUS_RDONLY, *dir);
|
||||
return OPENDIR_OK;
|
||||
} catch (Genode::Out_of_ram) {
|
||||
if (create) {
|
||||
@ -677,7 +722,7 @@ class Vfs::Ram_file_system : public Vfs::File_system
|
||||
link->lock();
|
||||
parent->adopt(link);
|
||||
link->unlock();
|
||||
|
||||
parent->notify(_io_handler);
|
||||
} else {
|
||||
|
||||
if (!node) return OPENLINK_ERR_LOOKUP_FAILED;
|
||||
@ -688,9 +733,8 @@ class Vfs::Ram_file_system : public Vfs::File_system
|
||||
}
|
||||
|
||||
try {
|
||||
*handle = new (alloc) Ram_vfs_handle(*this, alloc,
|
||||
Ram_vfs_handle::STATUS_RDWR,
|
||||
*link);
|
||||
*handle = new (alloc)
|
||||
Io_handle(*this, alloc, Io_handle::STATUS_RDWR, *link);
|
||||
return OPENLINK_OK;
|
||||
} catch (Genode::Out_of_ram) {
|
||||
if (create) {
|
||||
@ -709,13 +753,19 @@ class Vfs::Ram_file_system : public Vfs::File_system
|
||||
|
||||
void close(Vfs_handle *vfs_handle) override
|
||||
{
|
||||
Ram_vfs_handle *ram_handle =
|
||||
static_cast<Ram_vfs_handle *>(vfs_handle);
|
||||
Vfs_ram::Io_handle *ram_handle =
|
||||
static_cast<Vfs_ram::Io_handle *>(vfs_handle);
|
||||
|
||||
if (ram_handle) {
|
||||
if (!ram_handle->node.close_but_keep())
|
||||
destroy(_alloc, &ram_handle->node);
|
||||
destroy(vfs_handle->alloc(), ram_handle);
|
||||
Vfs_ram::Node &node = ram_handle->node;
|
||||
bool node_modified = ram_handle->modifying;
|
||||
|
||||
ram_handle->node.close(*ram_handle);
|
||||
destroy(vfs_handle->alloc(), ram_handle);
|
||||
|
||||
if (ram_handle->node.unlinked() && !ram_handle->node.opened()) {
|
||||
destroy(_alloc, &ram_handle->node);
|
||||
} else if (node_modified) {
|
||||
node.notify(_io_handler);
|
||||
}
|
||||
}
|
||||
|
||||
@ -797,6 +847,9 @@ class Vfs::Ram_file_system : public Vfs::File_system
|
||||
from_node->name(new_name);
|
||||
to_dir->adopt(from_node);
|
||||
|
||||
from_dir->notify(_io_handler);
|
||||
to_dir->notify(_io_handler);
|
||||
|
||||
return RENAME_OK;
|
||||
}
|
||||
|
||||
@ -813,6 +866,7 @@ class Vfs::Ram_file_system : public Vfs::File_system
|
||||
|
||||
node->lock();
|
||||
parent->release(node);
|
||||
parent->notify(_io_handler);
|
||||
remove(node);
|
||||
return UNLINK_OK;
|
||||
}
|
||||
@ -853,6 +907,35 @@ class Vfs::Ram_file_system : public Vfs::File_system
|
||||
static_cap_cast<Genode::Ram_dataspace>(ds_cap)); }
|
||||
|
||||
|
||||
Watch_result watch(char const *path,
|
||||
Vfs_watch_handle **handle,
|
||||
Allocator &alloc) override
|
||||
{
|
||||
using namespace Vfs_ram;
|
||||
|
||||
Node *node = lookup(path);
|
||||
if (!node) return WATCH_ERR_UNACCESSIBLE;
|
||||
Node::Guard guard(node);
|
||||
|
||||
try {
|
||||
Vfs_ram::Watch_handle *watch_handle = new(alloc)
|
||||
Vfs_ram::Watch_handle(*this, alloc, *node);
|
||||
node->open(*watch_handle);
|
||||
*handle = watch_handle;
|
||||
return WATCH_OK;
|
||||
}
|
||||
catch (Genode::Out_of_ram) { return WATCH_ERR_OUT_OF_RAM; }
|
||||
catch (Genode::Out_of_caps) { return WATCH_ERR_OUT_OF_CAPS; }
|
||||
}
|
||||
|
||||
void close(Vfs_watch_handle *vfs_handle) override
|
||||
{
|
||||
Vfs_ram::Watch_handle *watch_handle =
|
||||
static_cast<Vfs_ram::Watch_handle *>(vfs_handle);
|
||||
watch_handle->node.close(*watch_handle);
|
||||
destroy(watch_handle->alloc(), watch_handle);
|
||||
};
|
||||
|
||||
/************************
|
||||
** File I/O interface **
|
||||
************************/
|
||||
@ -864,11 +947,12 @@ class Vfs::Ram_file_system : public Vfs::File_system
|
||||
if ((vfs_handle->status_flags() & OPEN_MODE_ACCMODE) == OPEN_MODE_RDONLY)
|
||||
return WRITE_ERR_INVALID;
|
||||
|
||||
Ram_vfs_handle const *handle =
|
||||
static_cast<Ram_vfs_handle *>(vfs_handle);
|
||||
Vfs_ram::Io_handle *handle =
|
||||
static_cast<Vfs_ram::Io_handle *>(vfs_handle);
|
||||
|
||||
Vfs_ram::Node::Guard guard(&handle->node);
|
||||
out = handle->node.write(buf, len, handle->seek());
|
||||
handle->modifying = true;
|
||||
|
||||
return WRITE_OK;
|
||||
}
|
||||
@ -878,8 +962,8 @@ class Vfs::Ram_file_system : public Vfs::File_system
|
||||
{
|
||||
out_count = 0;
|
||||
|
||||
Ram_vfs_handle const *handle =
|
||||
static_cast<Ram_vfs_handle *>(vfs_handle);
|
||||
Vfs_ram::Io_handle const *handle =
|
||||
static_cast<Vfs_ram::Io_handle *>(vfs_handle);
|
||||
|
||||
Vfs_ram::Node::Guard guard(&handle->node);
|
||||
|
||||
@ -893,8 +977,8 @@ class Vfs::Ram_file_system : public Vfs::File_system
|
||||
if ((vfs_handle->status_flags() & OPEN_MODE_ACCMODE) == OPEN_MODE_RDONLY)
|
||||
return FTRUNCATE_ERR_NO_PERM;
|
||||
|
||||
Ram_vfs_handle const *handle =
|
||||
static_cast<Ram_vfs_handle *>(vfs_handle);
|
||||
Vfs_ram::Io_handle const *handle =
|
||||
static_cast<Vfs_ram::Io_handle *>(vfs_handle);
|
||||
|
||||
Vfs_ram::Node::Guard guard(&handle->node);
|
||||
|
||||
@ -903,6 +987,21 @@ class Vfs::Ram_file_system : public Vfs::File_system
|
||||
return FTRUNCATE_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify other handles if this handle has modified the node
|
||||
*/
|
||||
Sync_result complete_sync(Vfs_handle *vfs_handle) override
|
||||
{
|
||||
Vfs_ram::Io_handle *handle =
|
||||
static_cast<Vfs_ram::Io_handle *>(vfs_handle);
|
||||
if (handle->modifying) {
|
||||
handle->modifying = false;
|
||||
handle->node.close(*handle);
|
||||
handle->node.notify(_io_handler);
|
||||
handle->node.open(*handle);
|
||||
}
|
||||
return SYNC_OK;
|
||||
}
|
||||
|
||||
/***************************
|
||||
** File_system interface **
|
||||
|
@ -35,7 +35,7 @@ namespace Vfs_server {
|
||||
|
||||
class Session_component;
|
||||
class Root;
|
||||
class Io_response_handler;
|
||||
class Event_response_handler;
|
||||
|
||||
typedef Genode::Registered<Session_component> Registered_session;
|
||||
typedef Genode::Registry<Registered_session> Session_registry;
|
||||
@ -53,7 +53,7 @@ namespace Vfs_server {
|
||||
|
||||
|
||||
class Vfs_server::Session_component : public File_system::Session_rpc_object,
|
||||
public Node_io_handler
|
||||
public Session_io_handler
|
||||
{
|
||||
private:
|
||||
|
||||
@ -74,6 +74,8 @@ class Vfs_server::Session_component : public File_system::Session_rpc_object,
|
||||
*/
|
||||
Path const _root_path;
|
||||
|
||||
Genode::Session_label const _label;
|
||||
|
||||
bool const _writable;
|
||||
|
||||
/*
|
||||
@ -92,11 +94,11 @@ class Vfs_server::Session_component : public File_system::Session_rpc_object,
|
||||
* \throw Invalid_handle
|
||||
*/
|
||||
template <typename FUNC>
|
||||
void _apply(Node_handle handle, FUNC const &fn)
|
||||
void _apply_node(Node_handle handle, FUNC const &fn)
|
||||
{
|
||||
Node_space::Id id { handle.value };
|
||||
|
||||
try { _node_space.apply<Node>(id, fn); }
|
||||
try { return _node_space.apply<Node>(id, fn); }
|
||||
catch (Node_space::Unknown_id) { throw Invalid_handle(); }
|
||||
}
|
||||
|
||||
@ -155,7 +157,7 @@ class Vfs_server::Session_component : public File_system::Session_rpc_object,
|
||||
case Packet_descriptor::READ:
|
||||
|
||||
try {
|
||||
_apply(packet.handle(), [&] (Node &node) {
|
||||
_apply(packet.handle(), [&] (Io_node &node) {
|
||||
if (!node.read_ready()) {
|
||||
node.notify_read_ready(true);
|
||||
throw Not_ready();
|
||||
@ -178,7 +180,7 @@ class Vfs_server::Session_component : public File_system::Session_rpc_object,
|
||||
case Packet_descriptor::WRITE:
|
||||
|
||||
try {
|
||||
_apply(packet.handle(), [&] (Node &node) {
|
||||
_apply(packet.handle(), [&] (Io_node &node) {
|
||||
if (node.mode() & WRITE_ONLY) {
|
||||
res_length = node.write((char const *)content, length, seek);
|
||||
|
||||
@ -213,7 +215,7 @@ class Vfs_server::Session_component : public File_system::Session_rpc_object,
|
||||
break;
|
||||
|
||||
case Packet_descriptor::CONTENT_CHANGED:
|
||||
/* The VFS does not track file changes yet */
|
||||
Genode::warning("ignoring CONTENT_CHANGED packet from client");
|
||||
throw Dont_ack();
|
||||
|
||||
case Packet_descriptor::SYNC:
|
||||
@ -222,7 +224,7 @@ class Vfs_server::Session_component : public File_system::Session_rpc_object,
|
||||
* Sync the VFS and send any pending signals on the node.
|
||||
*/
|
||||
try {
|
||||
_apply(packet.handle(), [&] (Node &node) {
|
||||
_apply(packet.handle(), [&] (Io_node &node) {
|
||||
node.sync();
|
||||
succeeded = true;
|
||||
});
|
||||
@ -356,6 +358,8 @@ class Vfs_server::Session_component : public File_system::Session_rpc_object,
|
||||
destroy(_alloc, dir);
|
||||
else if (Symlink *link = dynamic_cast<Symlink*>(&node))
|
||||
destroy(_alloc, link);
|
||||
else if (Watch_node *watch = dynamic_cast<Watch_node*>(&node))
|
||||
destroy(_alloc, watch);
|
||||
else
|
||||
destroy(_alloc, &node);
|
||||
}
|
||||
@ -372,6 +376,7 @@ class Vfs_server::Session_component : public File_system::Session_rpc_object,
|
||||
*/
|
||||
|
||||
Session_component(Genode::Env &env,
|
||||
char const *label,
|
||||
Genode::Ram_quota ram_quota,
|
||||
Genode::Cap_quota cap_quota,
|
||||
size_t tx_buf_size,
|
||||
@ -387,6 +392,7 @@ class Vfs_server::Session_component : public File_system::Session_rpc_object,
|
||||
_process_packet_handler(env.ep(), *this, &Session_component::_process_packets),
|
||||
_vfs(vfs),
|
||||
_root_path(root_path),
|
||||
_label(label),
|
||||
_writable(writable)
|
||||
{
|
||||
/*
|
||||
@ -419,14 +425,20 @@ class Vfs_server::Session_component : public File_system::Session_rpc_object,
|
||||
* node-specific, for example after 'release_packet()' to signal
|
||||
* that a previously failed 'alloc_packet()' may succeed now.
|
||||
*/
|
||||
void handle_general_io()
|
||||
{
|
||||
_process_packets();
|
||||
}
|
||||
void handle_general_io() {
|
||||
_process_packets(); }
|
||||
|
||||
/* Node_io_handler interface */
|
||||
void handle_node_io(Node &node) override
|
||||
|
||||
/********************************
|
||||
** Node_io_handler interface **
|
||||
********************************/
|
||||
|
||||
void handle_node_io(Io_node &node) override
|
||||
{
|
||||
if (!tx_sink()->ready_to_ack())
|
||||
Genode::error(
|
||||
"dropping I/O notfication, congested packet buffer to '", _label, "'");
|
||||
|
||||
if (node.notify_read_ready() && node.read_ready()
|
||||
&& tx_sink()->ready_to_ack()) {
|
||||
Packet_descriptor packet(Packet_descriptor(),
|
||||
@ -440,6 +452,22 @@ class Vfs_server::Session_component : public File_system::Session_rpc_object,
|
||||
_process_packets();
|
||||
}
|
||||
|
||||
void handle_node_watch(Watch_node &node) override
|
||||
{
|
||||
if (!tx_sink()->ready_to_ack())
|
||||
Genode::error(
|
||||
"dropping watch notfication, congested packet buffer to '", _label, "'");
|
||||
|
||||
if (tx_sink()->ready_to_ack()) {
|
||||
Packet_descriptor packet(Packet_descriptor(),
|
||||
Node_handle { node.id().value },
|
||||
Packet_descriptor::CONTENT_CHANGED,
|
||||
0, 0);
|
||||
tx_sink()->acknowledge_packet(packet);
|
||||
}
|
||||
_process_packets();
|
||||
}
|
||||
|
||||
/***************************
|
||||
** File_system interface **
|
||||
***************************/
|
||||
@ -482,7 +510,7 @@ class Vfs_server::Session_component : public File_system::Session_rpc_object,
|
||||
_assert_valid_name(name_str);
|
||||
|
||||
return File_handle {
|
||||
dir.file(_node_space, _vfs, _alloc, *this, name_str, fs_mode, create).value
|
||||
dir.file(_node_space, _vfs, _alloc, name_str, fs_mode, create).value
|
||||
};
|
||||
});
|
||||
}
|
||||
@ -516,16 +544,47 @@ class Vfs_server::Session_component : public File_system::Session_rpc_object,
|
||||
|
||||
Node *node;
|
||||
|
||||
try { node = new (_alloc) Node(_node_space, path_str, STAT_ONLY,
|
||||
*this); }
|
||||
try { node = new (_alloc) Node(_node_space, path_str, *this); }
|
||||
catch (Out_of_memory) { throw Out_of_ram(); }
|
||||
|
||||
return Node_handle { node->id().value };
|
||||
}
|
||||
|
||||
Watch_handle watch(File_system::Path const &path) override
|
||||
{
|
||||
char const *path_str = path.string();
|
||||
|
||||
_assert_valid_path(path_str);
|
||||
|
||||
/* re-root the path */
|
||||
Path sub_path(path_str+1, _root_path.base());
|
||||
path_str = sub_path.base();
|
||||
|
||||
Vfs::Vfs_watch_handle *vfs_handle = nullptr;
|
||||
typedef Directory_service::Watch_result Result;
|
||||
switch (_vfs.watch(path_str, &vfs_handle, _alloc)) {
|
||||
case Result::WATCH_OK: break;
|
||||
case Result::WATCH_ERR_UNACCESSIBLE:
|
||||
throw Lookup_failed();
|
||||
case Result::WATCH_ERR_STATIC:
|
||||
throw Unavailable();
|
||||
case Result::WATCH_ERR_OUT_OF_RAM:
|
||||
throw Out_of_ram();
|
||||
case Result::WATCH_ERR_OUT_OF_CAPS:
|
||||
throw Out_of_caps();
|
||||
}
|
||||
|
||||
Node *node;
|
||||
try { node = new (_alloc)
|
||||
Watch_node(_node_space, path_str, *vfs_handle, *this); }
|
||||
catch (Out_of_memory) { throw Out_of_ram(); }
|
||||
|
||||
return Watch_handle { node->id().value };
|
||||
}
|
||||
|
||||
void close(Node_handle handle) override
|
||||
{
|
||||
try { _apply(handle, [&] (Node &node) {
|
||||
try { _apply_node(handle, [&] (Node &node) {
|
||||
_close(node);
|
||||
}); } catch (File_system::Invalid_handle) { }
|
||||
}
|
||||
@ -534,7 +593,7 @@ class Vfs_server::Session_component : public File_system::Session_rpc_object,
|
||||
{
|
||||
File_system::Status fs_stat;
|
||||
|
||||
_apply(node_handle, [&] (Node &node) {
|
||||
_apply_node(node_handle, [&] (Node &node) {
|
||||
Directory_service::Stat vfs_stat;
|
||||
|
||||
if (_vfs.stat(node.path(), vfs_stat) != Directory_service::STAT_OK)
|
||||
@ -615,15 +674,17 @@ class Vfs_server::Session_component : public File_system::Session_rpc_object,
|
||||
void control(Node_handle, Control) override { }
|
||||
};
|
||||
|
||||
|
||||
struct Vfs_server::Io_response_handler : Vfs::Io_response_handler
|
||||
/**
|
||||
* Global vfs event handler
|
||||
*/
|
||||
struct Vfs_server::Event_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)
|
||||
Event_response_handler(Session_registry &session_registry)
|
||||
: _session_registry(session_registry) { }
|
||||
|
||||
void handle_io_response(Vfs::Vfs_handle::Context *context) override
|
||||
@ -637,7 +698,7 @@ struct Vfs_server::Io_response_handler : Vfs::Io_response_handler
|
||||
_in_progress = true;
|
||||
|
||||
if (context)
|
||||
Node::node_by_context(*context).handle_io_response();
|
||||
Io_node::node_by_context(*context).handle_io_response();
|
||||
else
|
||||
_handle_general_io = true;
|
||||
|
||||
@ -650,6 +711,12 @@ struct Vfs_server::Io_response_handler : Vfs::Io_response_handler
|
||||
|
||||
_in_progress = false;
|
||||
}
|
||||
|
||||
void handle_watch_response(Vfs::Vfs_watch_handle::Context *context) override
|
||||
{
|
||||
if (context)
|
||||
Watch_node::node_by_context(*context).handle_watch_response();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -676,12 +743,12 @@ class Vfs_server::Root : public Genode::Root_component<Session_component>
|
||||
|
||||
Session_registry _session_registry { };
|
||||
|
||||
Io_response_handler _io_response_handler { _session_registry };
|
||||
Event_response_handler _response_handler { _session_registry };
|
||||
|
||||
Vfs::Global_file_system_factory _global_file_system_factory { _vfs_heap };
|
||||
|
||||
Vfs::Dir_file_system _vfs {
|
||||
_env, _vfs_heap, vfs_config(), _io_response_handler,
|
||||
_env, _vfs_heap, vfs_config(), _response_handler,
|
||||
_global_file_system_factory };
|
||||
|
||||
Genode::Signal_handler<Root> _config_handler {
|
||||
@ -774,7 +841,7 @@ class Vfs_server::Root : public Genode::Root_component<Session_component>
|
||||
}
|
||||
|
||||
Session_component *session = new (md_alloc())
|
||||
Registered_session(_session_registry, _env,
|
||||
Registered_session(_session_registry, _env, label.string(),
|
||||
Genode::Ram_quota{ram_quota},
|
||||
Genode::Cap_quota{cap_quota},
|
||||
tx_buf_size, _vfs,
|
||||
|
@ -29,16 +29,19 @@ namespace Vfs_server {
|
||||
using namespace File_system;
|
||||
using namespace Vfs;
|
||||
|
||||
struct Node;
|
||||
struct Directory;
|
||||
struct File;
|
||||
struct Symlink;
|
||||
class Node;
|
||||
class Io_node;
|
||||
class Watch_node;
|
||||
class Directory;
|
||||
class File;
|
||||
class Symlink;
|
||||
|
||||
typedef Genode::Id_space<Node> Node_space;
|
||||
|
||||
struct Node_io_handler : Interface
|
||||
struct Session_io_handler : Interface
|
||||
{
|
||||
virtual void handle_node_io(Node &node) = 0;
|
||||
virtual void handle_node_io(Io_node &node) = 0;
|
||||
virtual void handle_node_watch(Watch_node &node) = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -59,20 +62,21 @@ namespace Vfs_server {
|
||||
* Type trait for determining the node type for a given handle type
|
||||
*/
|
||||
template<typename T> struct Node_type;
|
||||
template<> struct Node_type<Node_handle> { typedef Node Type; };
|
||||
template<> struct Node_type<Dir_handle> { typedef Directory Type; };
|
||||
template<> struct Node_type<File_handle> { typedef File Type; };
|
||||
template<> struct Node_type<Symlink_handle> { typedef Symlink Type; };
|
||||
|
||||
template<> struct Node_type<Node_handle> { typedef Io_node Type; };
|
||||
template<> struct Node_type<Dir_handle> { typedef Directory Type; };
|
||||
template<> struct Node_type<File_handle> { typedef File Type; };
|
||||
template<> struct Node_type<Symlink_handle> { typedef Symlink Type; };
|
||||
template<> struct Node_type<Watch_handle> { typedef Watch_node Type; };
|
||||
|
||||
/**
|
||||
* Type trait for determining the handle type for a given node type
|
||||
*/
|
||||
template<typename T> struct Handle_type;
|
||||
template<> struct Handle_type<Node> { typedef Node_handle Type; };
|
||||
template<> struct Handle_type<Io_node> { typedef Node_handle Type; };
|
||||
template<> struct Handle_type<Directory> { typedef Dir_handle Type; };
|
||||
template<> struct Handle_type<File> { typedef File_handle Type; };
|
||||
template<> struct Handle_type<Symlink> { typedef Symlink_handle Type; };
|
||||
template<> struct Handle_type<Watch> { typedef Watch_handle Type; };
|
||||
|
||||
/*
|
||||
* Note that the file objects are created at the
|
||||
@ -82,10 +86,8 @@ namespace Vfs_server {
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
class Vfs_server::Node : public File_system::Node_base,
|
||||
private Node_space::Element,
|
||||
private Vfs::Vfs_handle::Context
|
||||
private Node_space::Element
|
||||
{
|
||||
public:
|
||||
|
||||
@ -100,6 +102,52 @@ class Vfs_server::Node : public File_system::Node_base,
|
||||
Node &operator = (Node const &);
|
||||
|
||||
Path const _path;
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
* I/O handler for session context
|
||||
*/
|
||||
Session_io_handler &_session_io_handler;
|
||||
|
||||
public:
|
||||
|
||||
Node(Node_space &space, char const *node_path,
|
||||
Session_io_handler &io_handler)
|
||||
:
|
||||
Node_space::Element(*this, space),
|
||||
_path(node_path),
|
||||
_session_io_handler(io_handler)
|
||||
{ }
|
||||
|
||||
virtual ~Node() { }
|
||||
|
||||
using Node_space::Element::id;
|
||||
|
||||
char const *path() const { return _path.base(); }
|
||||
|
||||
/**
|
||||
* Print for debugging
|
||||
*/
|
||||
void print(Genode::Output &out) const {
|
||||
out.out_string(_path.base()); }
|
||||
};
|
||||
|
||||
class Vfs_server::Io_node : public Vfs_server::Node,
|
||||
private Vfs::Vfs_handle::Context
|
||||
{
|
||||
public:
|
||||
|
||||
enum Op_state { IDLE, READ_QUEUED, SYNC_QUEUED };
|
||||
|
||||
private:
|
||||
|
||||
/*
|
||||
* Noncopyable
|
||||
*/
|
||||
Io_node(Io_node const &);
|
||||
Io_node &operator = (Io_node const &);
|
||||
|
||||
Mode const _mode;
|
||||
|
||||
bool _notify_read_ready = false;
|
||||
@ -108,7 +156,6 @@ class Vfs_server::Node : public File_system::Node_base,
|
||||
|
||||
Vfs::Vfs_handle::Context &context() { return *this; }
|
||||
|
||||
Node_io_handler &_node_io_handler;
|
||||
Vfs::Vfs_handle *_handle { nullptr };
|
||||
Op_state op_state { Op_state::IDLE };
|
||||
|
||||
@ -183,24 +230,19 @@ class Vfs_server::Node : public File_system::Node_base,
|
||||
|
||||
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)
|
||||
{ }
|
||||
Io_node(Node_space &space, char const *node_path, Mode node_mode,
|
||||
Session_io_handler &io_handler)
|
||||
: Node(space, node_path, io_handler), _mode(node_mode) { }
|
||||
|
||||
virtual ~Node() { }
|
||||
virtual ~Io_node() { }
|
||||
|
||||
using Node_space::Element::id;
|
||||
|
||||
static Node &node_by_context(Vfs::Vfs_handle::Context &context)
|
||||
static Io_node &node_by_context(Vfs::Vfs_handle::Context &context)
|
||||
{
|
||||
return static_cast<Node &>(context);
|
||||
return static_cast<Io_node &>(context);
|
||||
}
|
||||
|
||||
char const *path() { return _path.base(); }
|
||||
Mode mode() const { return _mode; }
|
||||
|
||||
virtual size_t read(char * /* dst */, size_t /* len */, seek_off_t)
|
||||
@ -211,10 +253,13 @@ class Vfs_server::Node : public File_system::Node_base,
|
||||
|
||||
bool read_ready() { return _handle->fs().read_ready(_handle); }
|
||||
|
||||
void handle_io_response()
|
||||
{
|
||||
_node_io_handler.handle_node_io(*this);
|
||||
}
|
||||
/**
|
||||
* The global handler has drawn an association from an I/O
|
||||
* context and this open node, now process the event at the
|
||||
* session for this node.
|
||||
*/
|
||||
void handle_io_response() {
|
||||
_session_io_handler.handle_node_io(*this); }
|
||||
|
||||
void notify_read_ready(bool requested)
|
||||
{
|
||||
@ -257,16 +302,67 @@ class Vfs_server::Node : public File_system::Node_base,
|
||||
}
|
||||
};
|
||||
|
||||
struct Vfs_server::Symlink : Node
|
||||
|
||||
class Vfs_server::Watch_node final : public Vfs_server::Node,
|
||||
private Vfs::Vfs_watch_handle::Context
|
||||
{
|
||||
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)
|
||||
private:
|
||||
|
||||
/*
|
||||
* Noncopyable
|
||||
*/
|
||||
Watch_node(Watch_node const &);
|
||||
Watch_node &operator = (Watch_node const &);
|
||||
|
||||
Vfs::Vfs_watch_handle &_watch_handle;
|
||||
|
||||
public:
|
||||
|
||||
Watch_node(Node_space &space, char const *path,
|
||||
Vfs::Vfs_watch_handle &handle,
|
||||
Session_io_handler &io_handler)
|
||||
:
|
||||
Node(space, path, io_handler),
|
||||
_watch_handle(handle)
|
||||
{
|
||||
/*
|
||||
* set the context so this Watch object
|
||||
* is passed back thru the Io_handler
|
||||
*/
|
||||
_watch_handle.context(this);
|
||||
}
|
||||
|
||||
~Watch_node()
|
||||
{
|
||||
_watch_handle.context((Vfs::Vfs_watch_handle::Context*)~0ULL);
|
||||
_watch_handle.fs().close(&_watch_handle);
|
||||
}
|
||||
|
||||
static Watch_node &node_by_context(Vfs::Vfs_watch_handle::Context &context)
|
||||
{
|
||||
return static_cast<Watch_node &>(context);
|
||||
}
|
||||
|
||||
/**
|
||||
* The global handler has drawn an association from a watch
|
||||
* context and this open node, now process the event at the
|
||||
* session for this node.
|
||||
*/
|
||||
void handle_watch_response() {
|
||||
_session_io_handler.handle_node_watch(*this); }
|
||||
};
|
||||
|
||||
|
||||
struct Vfs_server::Symlink : Io_node
|
||||
{
|
||||
Symlink(Node_space &space,
|
||||
Vfs::File_system &vfs,
|
||||
Genode::Allocator &alloc,
|
||||
Session_io_handler &node_io_handler,
|
||||
char const *link_path,
|
||||
Mode mode,
|
||||
bool create)
|
||||
: Io_node(space, link_path, mode, node_io_handler)
|
||||
{
|
||||
assert_openlink(vfs.openlink(link_path, create, &_handle, alloc));
|
||||
_handle->context = &context();
|
||||
@ -316,7 +412,7 @@ struct Vfs_server::Symlink : Node
|
||||
};
|
||||
|
||||
|
||||
class Vfs_server::File : public Node
|
||||
class Vfs_server::File : public Io_node
|
||||
{
|
||||
private:
|
||||
|
||||
@ -330,15 +426,15 @@ class Vfs_server::File : public Node
|
||||
|
||||
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)
|
||||
File(Node_space &space,
|
||||
Vfs::File_system &vfs,
|
||||
Genode::Allocator &alloc,
|
||||
Session_io_handler &node_io_handler,
|
||||
char const *file_path,
|
||||
Mode fs_mode,
|
||||
bool create)
|
||||
:
|
||||
Node(space, file_path, fs_mode, node_io_handler)
|
||||
Io_node(space, file_path, fs_mode, node_io_handler)
|
||||
{
|
||||
unsigned vfs_mode =
|
||||
(fs_mode-1) | (create ? Vfs::Directory_service::OPEN_MODE_CREATE : 0);
|
||||
@ -387,15 +483,15 @@ class Vfs_server::File : public Node
|
||||
};
|
||||
|
||||
|
||||
struct Vfs_server::Directory : Node
|
||||
struct Vfs_server::Directory : Io_node
|
||||
{
|
||||
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)
|
||||
Directory(Node_space &space,
|
||||
Vfs::File_system &vfs,
|
||||
Genode::Allocator &alloc,
|
||||
Session_io_handler &node_io_handler,
|
||||
char const *dir_path,
|
||||
bool create)
|
||||
: Io_node(space, dir_path, READ_ONLY, node_io_handler)
|
||||
{
|
||||
assert_opendir(vfs.opendir(dir_path, create, &_handle, alloc));
|
||||
_handle->context = &context();
|
||||
@ -406,7 +502,6 @@ struct Vfs_server::Directory : Node
|
||||
Node_space::Id file(Node_space &space,
|
||||
Vfs::File_system &vfs,
|
||||
Genode::Allocator &alloc,
|
||||
Node_io_handler &node_io_handler,
|
||||
char const *file_path,
|
||||
Mode mode,
|
||||
bool create)
|
||||
@ -416,8 +511,9 @@ struct Vfs_server::Directory : Node
|
||||
|
||||
File *file;
|
||||
try {
|
||||
file = new (alloc)
|
||||
File(space, vfs, alloc, node_io_handler, path_str, mode, create);
|
||||
file = new (alloc) File(space, vfs, alloc,
|
||||
_session_io_handler,
|
||||
path_str, mode, create);
|
||||
} catch (Out_of_memory) { throw Out_of_ram(); }
|
||||
|
||||
if (create)
|
||||
@ -436,7 +532,8 @@ struct Vfs_server::Directory : Node
|
||||
char const *path_str = subpath.base();
|
||||
|
||||
Symlink *link;
|
||||
try { link = new (alloc) Symlink(space, vfs, alloc, _node_io_handler,
|
||||
try { link = new (alloc) Symlink(space, vfs, alloc,
|
||||
_session_io_handler,
|
||||
path_str, mode, create); }
|
||||
catch (Out_of_memory) { throw Out_of_ram(); }
|
||||
if (create)
|
||||
|
Loading…
Reference in New Issue
Block a user