From f996697fd53b27f774f9688d37f6edb3ffe5ffd6 Mon Sep 17 00:00:00 2001 From: Emery Hemingway Date: Wed, 22 Jul 2015 00:32:42 -0500 Subject: [PATCH] VFS: local ram_fs instances Move FS Node implementations from server/ram_fs to include/ram_fs. Support embedded ram_fs instances in VFS configurations using . Add 'no space' handling to VFS symlink ops. Fixes #1635 --- repos/libports/run/libc_ram_vfs.run | 70 ++++ repos/libports/src/lib/libc/vfs_plugin.cc | 1 + .../os/{src/server => include}/ram_fs/chunk.h | 6 +- .../server => include}/ram_fs/directory.h | 23 +- .../os/{src/server => include}/ram_fs/file.h | 10 +- .../os/{src/server => include}/ram_fs/node.h | 6 +- .../{src/server => include}/ram_fs/symlink.h | 8 +- repos/os/include/vfs/directory_service.h | 4 +- repos/os/include/vfs/ram_file_system.h | 368 ++++++++++++++++++ repos/os/src/lib/vfs/file_system_factory.cc | 2 + repos/os/src/server/ram_fs/main.cc | 2 +- repos/os/src/test/ram_fs_chunk/main.cc | 4 +- 12 files changed, 474 insertions(+), 30 deletions(-) create mode 100644 repos/libports/run/libc_ram_vfs.run rename repos/os/{src/server => include}/ram_fs/chunk.h (98%) rename repos/os/{src/server => include}/ram_fs/directory.h (93%) rename repos/os/{src/server => include}/ram_fs/file.h (93%) rename repos/os/{src/server => include}/ram_fs/node.h (90%) rename repos/os/{src/server => include}/ram_fs/symlink.h (85%) create mode 100644 repos/os/include/vfs/ram_file_system.h diff --git a/repos/libports/run/libc_ram_vfs.run b/repos/libports/run/libc_ram_vfs.run new file mode 100644 index 000000000..d598cb68e --- /dev/null +++ b/repos/libports/run/libc_ram_vfs.run @@ -0,0 +1,70 @@ +# +# \brief Test for using the vfs local ram_fs +# \author Norman Feske +# \date 2014-04-10 +# +# \author Emery Hemingway +# \date 2015-07-21 +# + +# +# Build +# + +build { core init test/libc_vfs } + +create_boot_directory + +# +# Generate config +# + +install_config { + + + + + + + + + + + + + + + + + + + + + + + + + + + + +} + +# +# Boot modules +# + +build_boot_image { + core init + ld.lib.so libc.lib.so + test-libc_vfs +} + +# +# Execute test case +# + +append qemu_args " -m 128 -nographic " +run_genode_until {.*child "test-libc_vfs" exited with exit value 0.*} 60 + +# vi: set ft=tcl : diff --git a/repos/libports/src/lib/libc/vfs_plugin.cc b/repos/libports/src/lib/libc/vfs_plugin.cc index eeabcd311..56cc4309f 100644 --- a/repos/libports/src/lib/libc/vfs_plugin.cc +++ b/repos/libports/src/lib/libc/vfs_plugin.cc @@ -712,6 +712,7 @@ int Libc::Vfs_plugin::symlink(const char *oldpath, const char *newpath) case Result::SYMLINK_ERR_NO_ENTRY: errno = ENOENT; return -1; case Result::SYMLINK_ERR_NAME_TOO_LONG: errno = ENAMETOOLONG; return -1; case Result::SYMLINK_ERR_NO_PERM: errno = ENOSYS; return -1; + case Result::SYMLINK_ERR_NO_SPACE: errno = ENOSPC; return -1; case Result::SYMLINK_OK: break; } return 0; diff --git a/repos/os/src/server/ram_fs/chunk.h b/repos/os/include/ram_fs/chunk.h similarity index 98% rename from repos/os/src/server/ram_fs/chunk.h rename to repos/os/include/ram_fs/chunk.h index 4a2e130c5..9791d0dd2 100644 --- a/repos/os/src/server/ram_fs/chunk.h +++ b/repos/os/include/ram_fs/chunk.h @@ -11,8 +11,8 @@ * under the terms of the GNU General Public License version 2. */ -#ifndef _CHUNK_H_ -#define _CHUNK_H_ +#ifndef _INCLUDE__RAM_FS__CHUNK_H_ +#define _INCLUDE__RAM_FS__CHUNK_H_ /* Genode includes */ #include @@ -438,4 +438,4 @@ namespace File_system { }; }; -#endif /* _CHUNK_H_ */ +#endif /* _INCLUDE__RAM_FS__CHUNK_H_ */ diff --git a/repos/os/src/server/ram_fs/directory.h b/repos/os/include/ram_fs/directory.h similarity index 93% rename from repos/os/src/server/ram_fs/directory.h rename to repos/os/include/ram_fs/directory.h index 278737572..491ef2923 100644 --- a/repos/os/src/server/ram_fs/directory.h +++ b/repos/os/include/ram_fs/directory.h @@ -4,16 +4,16 @@ * \date 2012-04-11 */ -#ifndef _DIRECTORY_H_ -#define _DIRECTORY_H_ +#ifndef _INCLUDE__RAM_FS__DIRECTORY_H_ +#define _INCLUDE__RAM_FS__DIRECTORY_H_ /* Genode includes */ #include /* local includes */ -#include -#include -#include +#include +#include +#include namespace File_system { @@ -28,6 +28,13 @@ namespace File_system { Directory(char const *name) : _num_entries(0) { Node::name(name); } + Node *entry_unsynchronized(size_t index) + { + Node *node = _entries.first(); + for (unsigned i = 0; i < index && node; node = node->next(), i++); + return node; + } + bool has_sub_node_unsynchronized(char const *name) const { Node const *sub_node = _entries.first(); @@ -184,9 +191,7 @@ namespace File_system { return 0; } - /* find list element */ - Node *node = _entries.first(); - for (unsigned i = 0; i < index && node; node = node->next(), i++); + Node *node = entry_unsynchronized(index); /* index out of range */ if (!node) @@ -213,4 +218,4 @@ namespace File_system { }; } -#endif /* _DIRECTORY_H_ */ +#endif /* _INCLUDE__RAM_FS__DIRECTORY_H_ */ diff --git a/repos/os/src/server/ram_fs/file.h b/repos/os/include/ram_fs/file.h similarity index 93% rename from repos/os/src/server/ram_fs/file.h rename to repos/os/include/ram_fs/file.h index a54803a81..3f858984d 100644 --- a/repos/os/src/server/ram_fs/file.h +++ b/repos/os/include/ram_fs/file.h @@ -4,15 +4,15 @@ * \date 2012-04-11 */ -#ifndef _FILE_H_ -#define _FILE_H_ +#ifndef _INCLUDE__RAM_FS__FILE_H_ +#define _INCLUDE__RAM_FS__FILE_H_ /* Genode includes */ #include /* local includes */ -#include -#include +#include +#include namespace File_system { @@ -103,4 +103,4 @@ namespace File_system { }; } -#endif /* _FILE_H_ */ +#endif /* _INCLUDE__RAM_FS__FILE_H_ */ diff --git a/repos/os/src/server/ram_fs/node.h b/repos/os/include/ram_fs/node.h similarity index 90% rename from repos/os/src/server/ram_fs/node.h rename to repos/os/include/ram_fs/node.h index 3e0e3e8e8..72ff955f8 100644 --- a/repos/os/src/server/ram_fs/node.h +++ b/repos/os/include/ram_fs/node.h @@ -4,8 +4,8 @@ * \date 2012-04-11 */ -#ifndef _NODE_H_ -#define _NODE_H_ +#ifndef _INCLUDE__RAM_FS__NODE_H_ +#define _INCLUDE__RAM_FS__NODE_H_ /* Genode includes */ #include @@ -55,4 +55,4 @@ namespace File_system { } -#endif /* _NODE_H_ */ +#endif /* _INCLUDE__RAM_FS__NODE_H_ */ diff --git a/repos/os/src/server/ram_fs/symlink.h b/repos/os/include/ram_fs/symlink.h similarity index 85% rename from repos/os/src/server/ram_fs/symlink.h rename to repos/os/include/ram_fs/symlink.h index 93677accb..2d06a57f1 100644 --- a/repos/os/src/server/ram_fs/symlink.h +++ b/repos/os/include/ram_fs/symlink.h @@ -4,11 +4,11 @@ * \date 2012-04-11 */ -#ifndef _SYMLINK_H_ -#define _SYMLINK_H_ +#ifndef _INCLUDE__RAM_FS__SYMLINK_H_ +#define _INCLUDE__RAM_FS__SYMLINK_H_ /* local includes */ -#include +#include namespace File_system { @@ -44,4 +44,4 @@ namespace File_system { }; } -#endif /* _SYMLINK_H_ */ +#endif /* _INCLUDE__RAM_FS__SYMLINK_H_ */ diff --git a/repos/os/include/vfs/directory_service.h b/repos/os/include/vfs/directory_service.h index 7e300d944..ca66053ad 100644 --- a/repos/os/include/vfs/directory_service.h +++ b/repos/os/include/vfs/directory_service.h @@ -160,8 +160,8 @@ struct Vfs::Directory_service *************/ enum Symlink_result { SYMLINK_ERR_EXISTS, SYMLINK_ERR_NO_ENTRY, - SYMLINK_ERR_NAME_TOO_LONG, SYMLINK_ERR_NO_PERM, - SYMLINK_OK }; + SYMLINK_ERR_NO_SPACE, SYMLINK_ERR_NO_PERM, + SYMLINK_ERR_NAME_TOO_LONG, SYMLINK_OK }; virtual Symlink_result symlink(char const *from, char const *to) = 0; diff --git a/repos/os/include/vfs/ram_file_system.h b/repos/os/include/vfs/ram_file_system.h new file mode 100644 index 000000000..bd372ee1d --- /dev/null +++ b/repos/os/include/vfs/ram_file_system.h @@ -0,0 +1,368 @@ +/* + * \brief Embedded RAM VFS + * \author Emery Hemingway + * \date 2015-07-21 + */ + +/* + * Copyright (C) 2015 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 _INCLUDE__VFS__RAM_FILE_SYSTEM_H_ +#define _INCLUDE__VFS__RAM_FILE_SYSTEM_H_ + +#include +#include + +namespace Vfs { + using namespace ::File_system; + class Ram_file_system; +} + + +class Vfs::Ram_file_system : public File_system, private ::File_system::Directory +{ + private: + + struct Ram_vfs_handle : Vfs_handle + { + private: + + ::File_system::Node *_node; + + public: + + Ram_vfs_handle(File_system &fs, int status_flags, + ::File_system::Node *node) + : Vfs_handle(fs, fs, status_flags), _node(node) + { } + + ::File_system::Node *node() const { return _node; } + }; + + public: + + /** + * Constructor + */ + Ram_file_system(Xml_node config) + : Directory("/") { } + + /*************************** + ** File_system interface ** + ***************************/ + + static char const *name() { return "ram"; } + + void sync() { } + + /******************************** + ** File I/O service interface ** + ********************************/ + + Write_result write(Vfs_handle *vfs_handle, + char const *buf, file_size buf_size, + file_size &out_count) + { + Ram_vfs_handle const *handle = static_cast(vfs_handle); + + out_count = handle->node()->write(buf, buf_size, handle->seek()); + return WRITE_OK; + } + + Read_result read(Vfs_handle *vfs_handle, char *dst, file_size count, + file_size &out_count) + { + Ram_vfs_handle const *handle = static_cast(vfs_handle); + + out_count = handle->node()->read(dst, count, handle->seek()); + return READ_OK; + } + + Ftruncate_result ftruncate(Vfs_handle *vfs_handle, file_size len) + { + Ram_vfs_handle const *handle = static_cast(vfs_handle); + + File *file = dynamic_cast(handle->node()); + if (!file) + return FTRUNCATE_ERR_INTERRUPT; + + file->truncate(len); + return FTRUNCATE_OK; + } + + void register_read_ready_sigh(Vfs_handle *vfs_handle, + Signal_context_capability sigh) + { } + + + /********************************* + ** Directory service interface ** + *********************************/ + + Dataspace_capability dataspace(char const *path) + { + Ram_dataspace_capability ds_cap; + char *local_addr = 0; + try { + File *file = lookup_and_lock_file(path); + Node_lock_guard guard(file); + + ds_cap = env()->ram_session()->alloc(file->length()); + + local_addr = env()->rm_session()->attach(ds_cap); + file->read(local_addr, file->length(), 0); + env()->rm_session()->detach(local_addr); + + } catch(...) { + env()->rm_session()->detach(local_addr); + env()->ram_session()->free(ds_cap); + return Dataspace_capability(); + } + return ds_cap; + } + + void release(char const *path, Dataspace_capability ds_cap) + { + env()->ram_session()->free(static_cap_cast(ds_cap)); + } + + Open_result open(char const *path, unsigned mode, Vfs_handle **handle) + { + bool const create = mode & OPEN_MODE_CREATE; + char const *name = basename(++path); + Node *node; + + try { + if (create) { + Directory *parent = lookup_and_lock_parent(path); + Node_lock_guard parent_guard(parent); + + if (parent->has_sub_node_unsynchronized(name)) + return OPEN_ERR_EXISTS; + + node = new (env()->heap()) + File(*env()->heap(), name); + + parent->adopt_unsynchronized(node); + + } else { + node = lookup_and_lock(path); + node->unlock(); + } + } catch (Lookup_failed) { + return OPEN_ERR_UNACCESSIBLE; + } + + *handle = new (env()->heap()) + Ram_vfs_handle(*this, mode, node); + + return OPEN_OK; + } + + Stat_result stat(char const *path, Stat &stat) + { + try { + Node *node = lookup_and_lock(++path); + Node_lock_guard node_guard(node); + + memset(&stat, 0x00, sizeof(stat)); + stat.inode = node->inode(); + + File *file = dynamic_cast(node); + if (file) { + stat.size = file->length(); + stat.mode = STAT_MODE_FILE | 0777; + return STAT_OK; + } + + Directory *dir = dynamic_cast(node); + if (dir) { + stat.size = dir->num_entries(); + stat.mode = STAT_MODE_DIRECTORY | 0777; + return STAT_OK; + } + + Symlink *symlink = dynamic_cast(node); + if (symlink) { + stat.size = symlink->length(); + stat.mode = STAT_MODE_SYMLINK | 0777; + return STAT_OK; + } + + } catch (Lookup_failed) { } + return STAT_ERR_NO_ENTRY; + } + + Dirent_result dirent(char const *path, file_offset index, Dirent &dirent) + { + try { + Directory *dir = lookup_and_lock_dir(++path); + Node_lock_guard guard(dir); + + Node *node = dir->entry_unsynchronized(index); + if (!node) { + dirent.fileno = 0; + dirent.type = DIRENT_TYPE_END; + dirent.name[0] = '\0'; + return DIRENT_OK; + } + + dirent.fileno = index+1; + + if (dynamic_cast(node)) + dirent.type = DIRENT_TYPE_FILE; + else if (dynamic_cast(node)) + dirent.type = DIRENT_TYPE_DIRECTORY; + else if (dynamic_cast(node)) + dirent.type = DIRENT_TYPE_SYMLINK; + + strncpy(dirent.name, node->name(), sizeof(dirent.name)); + + } catch (Lookup_failed) { + return DIRENT_ERR_INVALID_PATH; + } + return DIRENT_OK; + } + + Unlink_result unlink(char const *path) + { + try { + Directory *parent = lookup_and_lock_parent(++path); + Node_lock_guard parent_guard(parent); + + char const *name = basename(path); + + Node *node = parent->lookup_and_lock(name); + parent->discard_unsynchronized(node); + destroy(env()->heap(), node); + } catch (Lookup_failed) { + return UNLINK_ERR_NO_ENTRY; + } + return UNLINK_OK; + } + + Readlink_result readlink(char const *path, char *buf, + file_size buf_size, file_size &out_len) + { + try { + Symlink *symlink = lookup_and_lock_symlink(++path); + Node_lock_guard guard(symlink); + + out_len = symlink->read(buf, buf_size, 0); + } catch (Lookup_failed) { + return READLINK_ERR_NO_ENTRY; + } + return READLINK_OK; + } + + Rename_result rename(char const *from, char const *to) + { + try { + Directory *from_dir = lookup_and_lock_parent(++from); + Node_lock_guard from_guard(from_dir); + Directory *to_dir = lookup_and_lock_parent(++to); + Node_lock_guard to_guard(to_dir); + + Node *node = from_dir->lookup_and_lock(basename(from)); + Node_lock_guard guard(node); + + from_dir->discard_unsynchronized(node); + node->name(basename(to)); + to_dir->adopt_unsynchronized(node); + + } catch (Lookup_failed) { + return RENAME_ERR_NO_ENTRY; + } + return RENAME_OK; + } + + Mkdir_result mkdir(char const *path, unsigned mode) + { + try { + Directory *parent = lookup_and_lock_parent(++path); + Node_lock_guard parent_guard(parent); + + char const *name = basename(path); + + if (strlen(name) > MAX_NAME_LEN) + return MKDIR_ERR_NAME_TOO_LONG; + + if (parent->has_sub_node_unsynchronized(name)) + return MKDIR_ERR_EXISTS; + + parent->adopt_unsynchronized(new (env()->heap()) + Directory(name)); + + } catch (Lookup_failed) { + return MKDIR_ERR_NO_ENTRY; + } catch (Allocator::Out_of_memory) { + return MKDIR_ERR_NO_SPACE; + } + return MKDIR_OK; + } + + Symlink_result symlink(char const *from, char const *to) + { + try { + Directory *parent = lookup_and_lock_parent(++to); + Node_lock_guard parent_guard(parent); + + char const *name = basename(to); + + if (strlen(name) > MAX_NAME_LEN) + return SYMLINK_ERR_NAME_TOO_LONG; + + if (parent->has_sub_node_unsynchronized(name)) + return SYMLINK_ERR_EXISTS; + + Symlink * const symlink = new (env()->heap()) + Symlink(name); + + parent->adopt_unsynchronized(symlink); + symlink->write(from, strlen(from), 0); + + } catch (Lookup_failed) { + return SYMLINK_ERR_NO_ENTRY; + } catch (Allocator::Out_of_memory) { + return SYMLINK_ERR_NO_SPACE; + } + return SYMLINK_OK; + } + + file_size num_dirent(char const *path) + { + try { + Directory *dir = lookup_and_lock_dir(++path); + Node_lock_guard guard(dir); + return dir->num_entries(); + } catch (Lookup_failed) { + return 0; + } + } + + bool is_directory(char const *path) + { + try { + lookup_and_lock_dir(++path)->unlock(); + return true; + } catch (...) { + return false; + } + } + + char const *leaf_path(char const *path) + { + try { + lookup_and_lock(path+1)->unlock(); + return path; + } catch (...) { } + return 0; + } + +}; + +#endif /* _INCLUDE__VFS__RAM_FILE_SYSTEM_H_ */ diff --git a/repos/os/src/lib/vfs/file_system_factory.cc b/repos/os/src/lib/vfs/file_system_factory.cc index 23cf19e3d..17b9a25aa 100644 --- a/repos/os/src/lib/vfs/file_system_factory.cc +++ b/repos/os/src/lib/vfs/file_system_factory.cc @@ -26,6 +26,7 @@ #include #include #include +#include class Default_file_system_factory : public Vfs::Global_file_system_factory @@ -199,6 +200,7 @@ class Default_file_system_factory : public Vfs::Global_file_system_factory _add_builtin_fs(); _add_builtin_fs(); _add_builtin_fs(); + _add_builtin_fs(); } }; diff --git a/repos/os/src/server/ram_fs/main.cc b/repos/os/src/server/ram_fs/main.cc index 41399e0b4..d09372a36 100644 --- a/repos/os/src/server/ram_fs/main.cc +++ b/repos/os/src/server/ram_fs/main.cc @@ -22,7 +22,7 @@ #include /* local includes */ -#include +#include /************************* diff --git a/repos/os/src/test/ram_fs_chunk/main.cc b/repos/os/src/test/ram_fs_chunk/main.cc index 84e3fb2f7..389b6541f 100644 --- a/repos/os/src/test/ram_fs_chunk/main.cc +++ b/repos/os/src/test/ram_fs_chunk/main.cc @@ -7,9 +7,7 @@ /* Genode includes */ #include #include - -/* local 'ram_fs' include */ -#include +#include namespace File_system { typedef Chunk<2> Chunk_level_3;