vfs: decouple file-system factory from libc

This patch moves the VFS file-system factory to a separate vfs library
that is independent from libc. This enables libc-less Genode programs to
easily use the VFS infrastructure.

Fixes #1561
This commit is contained in:
Norman Feske 2014-11-26 18:07:03 +01:00 committed by Christian Helmuth
parent 435721ea19
commit e3be65833f
10 changed files with 261 additions and 239 deletions

View File

@ -1,39 +0,0 @@
/*
* \brief vfs plugin interface
* \author Josef Soentgen
* \date 2014-08-19
*/
/*
* Copyright (C) 2014 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _LIBC_PLUGIN__VFS_H_
#define _LIBC_PLUGIN__VFS_H_
/* Genode includes */
#include <vfs/file_system.h>
#include <util/xml_node.h>
namespace Libc {
struct File_system_factory;
typedef Libc::File_system_factory*(*File_system_factory_func)(void);
}
struct Libc::File_system_factory
{
char const * const name;
File_system_factory(char const *name) : name(name) { }
virtual Vfs::File_system *create(Genode::Xml_node node) = 0;
virtual bool matches(Genode::Xml_node node) const {
return node.has_type(name); }
};
#endif /* _LIBC_PLUGIN__VFS_H_ */

View File

@ -4,7 +4,7 @@
LIBS = libc-string libc-locale libc-stdlib libc-stdio libc-gen libc-gdtoa \ LIBS = libc-string libc-locale libc-stdlib libc-stdio libc-gen libc-gdtoa \
libc-inet libc-stdtime libc-regex libc-compat libc-setjmp libc-inet libc-stdtime libc-regex libc-compat libc-setjmp
LIBS += base config LIBS += base config vfs
# #
# Back end # Back end

View File

@ -17,18 +17,6 @@
#include <vfs/dir_file_system.h> #include <vfs/dir_file_system.h>
#include <os/config.h> #include <os/config.h>
/* supported builtin file systems */
#include <vfs/tar_file_system.h>
#include <vfs/fs_file_system.h>
#include <vfs/terminal_file_system.h>
#include <vfs/null_file_system.h>
#include <vfs/zero_file_system.h>
#include <vfs/block_file_system.h>
#include <vfs/log_file_system.h>
#include <vfs/rom_file_system.h>
#include <vfs/inline_file_system.h>
#include <vfs/rtc_file_system.h>
/* libc includes */ /* libc includes */
#include <errno.h> #include <errno.h>
#include <dirent.h> #include <dirent.h>
@ -46,7 +34,6 @@
/* libc plugin interface */ /* libc plugin interface */
#include <libc-plugin/plugin.h> #include <libc-plugin/plugin.h>
#include <libc-plugin/fd_alloc.h> #include <libc-plugin/fd_alloc.h>
#include <libc-plugin/vfs.h>
/* libc-internal includes */ /* libc-internal includes */
#include <libc_mem_alloc.h> #include <libc_mem_alloc.h>
@ -87,119 +74,6 @@ static void vfs_stat_to_libc_stat_struct(Vfs::Directory_service::Stat const &src
} }
class Libc_file_system_factory : public Vfs::File_system_factory
{
private:
struct Entry_base : Libc::File_system_factory,
Genode::List<Entry_base>::Element
{
Entry_base(char const *name) : File_system_factory(name) { }
};
template <typename FILE_SYSTEM>
struct Builtin_entry : Entry_base
{
Builtin_entry() : Entry_base(FILE_SYSTEM::name()) { }
Vfs::File_system *create(Genode::Xml_node node) override
{
return new (Genode::env()->heap()) FILE_SYSTEM(node);
}
};
struct External_entry : Entry_base
{
Libc::File_system_factory &_fs;
External_entry(char const *name, Libc::File_system_factory_func func)
: Entry_base(name), _fs(*func()) { }
Vfs::File_system *create(Genode::Xml_node node) override {
return _fs.create(node); }
bool matches(Genode::Xml_node node) const override {
return node.has_type(_fs.name); }
};
Genode::List<Entry_base> _list;
template <typename FILE_SYSTEM>
void _add_builtin_fs()
{
_list.insert(new (Genode::env()->heap()) Builtin_entry<FILE_SYSTEM>());
}
Vfs::File_system *_try_create(Genode::Xml_node node)
{
for (Entry_base *e = _list.first(); e; e = e->next())
if (e->matches(node))
return e->create(node);
return 0;
}
bool _probe_lib(Genode::Xml_node node)
{
enum { MAX_LIB_NAME = 64, MAX_NAME = 32 };
char lib_name[MAX_LIB_NAME];
char name[MAX_NAME];
node.type_name(name, sizeof(name));
Genode::snprintf(lib_name, sizeof(lib_name), "vfs_%s.lib.so", name);
void *lib = dlopen(lib_name, RTLD_LAZY);
if (!lib) {
PWRN("could not open '%s'", lib_name);
return false;
}
Libc::File_system_factory_func func = (Libc::File_system_factory_func)
dlsym(lib, "Libc_file_system_factory");
if (!func) {
PWRN("could not find symbol 'Libc_file_system_factory' in '%s'", lib_name);
dlclose(lib);
return false;
}
_list.insert(new (Genode::env()->heap()) External_entry(name, func));
return true;
}
public:
Vfs::File_system *create(Genode::Xml_node node) override
{
/* try if type is handled by the currently registered fs types */
if (Vfs::File_system *fs = _try_create(node))
return fs;
/* probe for file system implementation available as shared lib */
if (_probe_lib(node)) {
/* try again with the new file system type loaded */
if (Vfs::File_system *fs = _try_create(node))
return fs;
}
return 0;
}
Libc_file_system_factory()
{
_add_builtin_fs<Vfs::Tar_file_system>();
_add_builtin_fs<Vfs::Fs_file_system>();
_add_builtin_fs<Vfs::Terminal_file_system>();
_add_builtin_fs<Vfs::Null_file_system>();
_add_builtin_fs<Vfs::Zero_file_system>();
_add_builtin_fs<Vfs::Block_file_system>();
_add_builtin_fs<Vfs::Log_file_system>();
_add_builtin_fs<Vfs::Rom_file_system>();
_add_builtin_fs<Vfs::Inline_file_system>();
_add_builtin_fs<Vfs::Rtc_file_system>();
}
};
namespace Libc { namespace Libc {
Genode::Xml_node config() __attribute__((weak)); Genode::Xml_node config() __attribute__((weak));
@ -283,8 +157,6 @@ class Libc::Vfs_plugin : public Libc::Plugin
{ {
private: private:
Libc_file_system_factory _fs_factory;
Vfs::Dir_file_system _root_dir; Vfs::Dir_file_system _root_dir;
Genode::Xml_node _vfs_config() Genode::Xml_node _vfs_config()
@ -327,7 +199,7 @@ class Libc::Vfs_plugin : public Libc::Plugin
/** /**
* Constructor * Constructor
*/ */
Vfs_plugin() : _root_dir(_vfs_config(), _fs_factory) Vfs_plugin() : _root_dir(_vfs_config(), Vfs::global_file_system_factory())
{ {
chdir(initial_cwd()); chdir(initial_cwd());

View File

@ -12,24 +12,22 @@
*/ */
/* Genode includes */ /* Genode includes */
#include <libc-plugin/vfs.h> #include <vfs/file_system_factory.h>
/* local includes */ /* local includes */
#include <vfs_jitterentropy.h> #include <vfs_jitterentropy.h>
struct Jitterentropy_factory : Libc::File_system_factory struct Jitterentropy_factory : Vfs::File_system_factory
{ {
Jitterentropy_factory() : File_system_factory("jitterentropy") { } Vfs::File_system *create(Genode::Xml_node node) override
Vfs::File_system *create(Genode::Xml_node node)
{ {
return new (Genode::env()->heap()) Jitterentropy_file_system(node); return new (Genode::env()->heap()) Jitterentropy_file_system(node);
} }
}; };
extern "C" Libc::File_system_factory *Libc_file_system_factory(void) extern "C" Vfs::File_system_factory *vfs_file_system_factory(void)
{ {
static Jitterentropy_factory factory; static Jitterentropy_factory factory;
return &factory; return &factory;

View File

@ -16,7 +16,16 @@
#include <vfs/file_system.h> #include <vfs/file_system.h>
namespace Vfs { class File_system_factory; } namespace Vfs {
struct File_system_factory;
struct Global_file_system_factory;
/**
* Return singleton instance of a file-system factory
*/
Global_file_system_factory &global_file_system_factory();
}
struct Vfs::File_system_factory struct Vfs::File_system_factory
@ -24,4 +33,17 @@ struct Vfs::File_system_factory
virtual File_system *create(Xml_node node) = 0; virtual File_system *create(Xml_node node) = 0;
}; };
struct Vfs::Global_file_system_factory : File_system_factory
{
/**
* Register an additional factory for new file-system type
*
* \name name of file-system type
* \factory factory to create instances of this file-system type
*/
virtual void extend(char const *name, File_system_factory &factory) = 0;
};
#endif /* _INCLUDE__VFS__FILE_SYSTEM_FACTORY_H_ */ #endif /* _INCLUDE__VFS__FILE_SYSTEM_FACTORY_H_ */

3
repos/os/lib/mk/vfs.mk Normal file
View File

@ -0,0 +1,3 @@
SRC_CC += file_system_factory.cc
vpath %.cc $(REP_DIR)/src/lib/vfs

View File

@ -0,0 +1,213 @@
/*
* \brief File-system factory implementation
* \author Norman Feske
* \date 2014-04-09
*/
/*
* Copyright (C) 2014 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* Genode includes */
#include <vfs/file_system_factory.h>
#include <base/shared_object.h>
/* supported builtin file systems */
#include <vfs/tar_file_system.h>
#include <vfs/fs_file_system.h>
#include <vfs/terminal_file_system.h>
#include <vfs/null_file_system.h>
#include <vfs/zero_file_system.h>
#include <vfs/block_file_system.h>
#include <vfs/log_file_system.h>
#include <vfs/rom_file_system.h>
#include <vfs/inline_file_system.h>
#include <vfs/rtc_file_system.h>
class Default_file_system_factory : public Vfs::Global_file_system_factory
{
private:
typedef Genode::String<128> Fs_type_name;
typedef Genode::String<128> Node_name;
typedef Genode::String<128> Library_name;
struct Entry_base : Vfs::File_system_factory,
Genode::List<Entry_base>::Element
{
Fs_type_name name;
Entry_base(Fs_type_name const &name) : name(name) { }
bool matches(Genode::Xml_node node) const {
return node.has_type(name.string()); }
};
template <typename FILE_SYSTEM>
struct Builtin_entry : Entry_base
{
Builtin_entry() : Entry_base(FILE_SYSTEM::name()) { }
Vfs::File_system *create(Genode::Xml_node node) override
{
return new (Genode::env()->heap()) FILE_SYSTEM(node);
}
};
struct External_entry : Entry_base
{
File_system_factory &_fs_factory;
External_entry(Fs_type_name const &name,
Vfs::File_system_factory &fs_factory)
:
Entry_base(name), _fs_factory(fs_factory) { }
Vfs::File_system *create(Genode::Xml_node node) override {
return _fs_factory.create(node); }
};
Genode::List<Entry_base> _list;
template <typename FILE_SYSTEM>
void _add_builtin_fs()
{
_list.insert(new (Genode::env()->heap()) Builtin_entry<FILE_SYSTEM>());
}
Vfs::File_system *_try_create(Genode::Xml_node node)
{
for (Entry_base *e = _list.first(); e; e = e->next())
if (e->matches(node))
return e->create(node);
return 0;
}
/**
* Return name of factory provided by the shared library
*/
static char const *_factory_symbol()
{
return "vfs_file_system_factory";
}
/**
* Return name of VFS node
*/
Node_name _node_name(Genode::Xml_node node)
{
char node_name [Node_name::capacity()];
node.type_name(node_name, sizeof(node_name));
return Node_name(node_name);
}
/**
* Return matching library name for a given vfs node name
*/
Library_name _library_name(Node_name const &node_name)
{
char lib_name [Library_name::capacity()];
Genode::snprintf(lib_name, sizeof(lib_name), "vfs_%s.lib.so",
node_name.string());
return Library_name(lib_name);
}
class Factory_not_available { };
/**
* \throw Factory_not_available
*/
Vfs::File_system_factory &_load_factory(Library_name const &lib_name)
{
Genode::Shared_object *shared_object = nullptr;
try {
shared_object = new (Genode::env()->heap())
Genode::Shared_object(lib_name.string());
typedef Vfs::File_system_factory *(*Query_fn)();
Query_fn query_fn = shared_object->lookup<Query_fn>(_factory_symbol());
return *query_fn();
} catch (Genode::Shared_object::Invalid_file) {
PWRN("could not open '%s'", lib_name.string());
throw Factory_not_available();
} catch (Genode::Shared_object::Invalid_symbol) {
PWRN("could not find symbol '%s' in '%s'",
_factory_symbol(), lib_name.string());
Genode::destroy(Genode::env()->heap(), shared_object);
throw Factory_not_available();
}
}
bool _probe_external_factory(Genode::Xml_node node)
{
Library_name const lib_name = _library_name(_node_name(node));
try {
_list.insert(new (Genode::env()->heap())
External_entry(_node_name(node).string(), _load_factory(lib_name)));
return true;
} catch (Factory_not_available) { return false; }
}
public:
Vfs::File_system *create(Genode::Xml_node node) override
{
/* try if type is handled by the currently registered fs types */
if (Vfs::File_system *fs = _try_create(node))
return fs;
/* probe for file system implementation available as shared lib */
if (_probe_external_factory(node)) {
/* try again with the new file system type loaded */
if (Vfs::File_system *fs = _try_create(node))
return fs;
}
return 0;
}
void extend(char const *name, File_system_factory &factory) override
{
_list.insert(new (Genode::env()->heap())
External_entry(name, factory));
}
Default_file_system_factory()
{
_add_builtin_fs<Vfs::Tar_file_system>();
_add_builtin_fs<Vfs::Fs_file_system>();
_add_builtin_fs<Vfs::Terminal_file_system>();
_add_builtin_fs<Vfs::Null_file_system>();
_add_builtin_fs<Vfs::Zero_file_system>();
_add_builtin_fs<Vfs::Block_file_system>();
_add_builtin_fs<Vfs::Log_file_system>();
_add_builtin_fs<Vfs::Rom_file_system>();
_add_builtin_fs<Vfs::Inline_file_system>();
_add_builtin_fs<Vfs::Rtc_file_system>();
}
};
namespace Vfs {
Global_file_system_factory &global_file_system_factory()
{
static Default_file_system_factory inst;
return inst;
}
}

View File

@ -1031,58 +1031,15 @@ void *operator new (Genode::size_t size) {
return Genode::env()->heap()->alloc(size); } return Genode::env()->heap()->alloc(size); }
class File_system_factory : public Vfs::File_system_factory
{
public:
struct Entry_base : Genode::List<Entry_base>::Element
{
char const * const name;
Entry_base(char const *name) : name(name) { }
virtual Vfs::File_system *create(Genode::Xml_node node) = 0;
bool matches(Genode::Xml_node node) const
{
return node.has_type(name);
}
};
template <typename FILE_SYSTEM> template <typename FILE_SYSTEM>
struct Entry : Entry_base struct File_system_factory : Vfs::File_system_factory
{ {
Entry(char const *name) : Entry_base(name) { } Vfs::File_system *create(Genode::Xml_node node)
Vfs::File_system *create(Genode::Xml_node node) override
{ {
return new FILE_SYSTEM(node); return new FILE_SYSTEM(node);
} }
}; };
private:
Genode::List<Entry_base> _list;
public:
template <typename FS>
void add_fs_type()
{
_list.insert(new Entry<FS>(FS::name()));
}
Vfs::File_system *create(Genode::Xml_node node) override
{
for (Entry_base *e = _list.first(); e; e = e->next())
if (e->matches(node))
return e->create(node);
return 0;
}
};
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
@ -1108,18 +1065,14 @@ int main(int argc, char **argv)
verbose = config()->xml_node().attribute("verbose").has_value("yes"); verbose = config()->xml_node().attribute("verbose").has_value("yes");
} catch (Xml_node::Nonexistent_attribute) { } } catch (Xml_node::Nonexistent_attribute) { }
/* register file systems */ /* register additional file systems to the VFS */
static File_system_factory fs_factory; Vfs::Global_file_system_factory &fs_factory = Vfs::global_file_system_factory();
fs_factory.add_fs_type<Vfs::Tar_file_system>();
fs_factory.add_fs_type<Vfs::Fs_file_system>(); File_system_factory<Stdio_file_system> stdio_file_system_factory;
fs_factory.add_fs_type<Vfs::Terminal_file_system>(); File_system_factory<Random_file_system> random_file_system_factory;
fs_factory.add_fs_type<Vfs::Null_file_system>();
fs_factory.add_fs_type<Vfs::Zero_file_system>(); fs_factory.extend("stdio", stdio_file_system_factory);
fs_factory.add_fs_type<Vfs::Block_file_system>(); fs_factory.extend("random", random_file_system_factory);
fs_factory.add_fs_type<Vfs::Block_file_system>();
fs_factory.add_fs_type<Vfs::Rtc_file_system>();
fs_factory.add_fs_type<Stdio_file_system>();
fs_factory.add_fs_type<Random_file_system>();
/* initialize virtual file system */ /* initialize virtual file system */
static Vfs::Dir_file_system static Vfs::Dir_file_system

View File

@ -1,5 +1,5 @@
TARGET = noux TARGET = noux
LIBS = base alarm config LIBS = alarm config vfs ld
SRC_CC = main.cc dummy_net.cc SRC_CC = main.cc dummy_net.cc
INC_DIR += $(PRG_DIR) INC_DIR += $(PRG_DIR)
INC_DIR += $(PRG_DIR)/../ INC_DIR += $(PRG_DIR)/../

View File

@ -1,5 +1,5 @@
TARGET = noux_net TARGET = noux_net
LIBS += alarm libc libc_lwip_nic_dhcp config LIBS += alarm libc libc_lwip_nic_dhcp config vfs
SRC_CC = main.cc net.cc SRC_CC = main.cc net.cc